Browse code

avfilter: add aderivative and aintegral filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2018/05/14 17:07:44
Showing 6 changed files
... ...
@@ -6,6 +6,7 @@ version <next>:
6 6
 - tmix filter
7 7
 - amplify filter
8 8
 - fftdnoiz filter
9
+- aderivative and aintegral audio filters
9 10
 
10 11
 
11 12
 version 4.0:
... ...
@@ -585,6 +585,12 @@ adelay=0|500S|700S
585 585
 @end example
586 586
 @end itemize
587 587
 
588
+@section aderivative, aintegral
589
+
590
+Compute derivative/integral of audio stream.
591
+
592
+Applying both filters one after another produces original audio.
593
+
588 594
 @section aecho
589 595
 
590 596
 Apply echoing to the input audio.
... ...
@@ -35,6 +35,7 @@ OBJS-$(CONFIG_ACOPY_FILTER)                  += af_acopy.o
35 35
 OBJS-$(CONFIG_ACROSSFADE_FILTER)             += af_afade.o
36 36
 OBJS-$(CONFIG_ACRUSHER_FILTER)               += af_acrusher.o
37 37
 OBJS-$(CONFIG_ADELAY_FILTER)                 += af_adelay.o
38
+OBJS-$(CONFIG_ADERIVATIVE_FILTER)            += af_aderivative.o
38 39
 OBJS-$(CONFIG_AECHO_FILTER)                  += af_aecho.o
39 40
 OBJS-$(CONFIG_AEMPHASIS_FILTER)              += af_aemphasis.o
40 41
 OBJS-$(CONFIG_AEVAL_FILTER)                  += aeval.o
... ...
@@ -44,6 +45,7 @@ OBJS-$(CONFIG_AFIR_FILTER)                   += af_afir.o
44 44
 OBJS-$(CONFIG_AFORMAT_FILTER)                += af_aformat.o
45 45
 OBJS-$(CONFIG_AGATE_FILTER)                  += af_agate.o
46 46
 OBJS-$(CONFIG_AIIR_FILTER)                   += af_aiir.o
47
+OBJS-$(CONFIG_AINTEGRAL_FILTER)              += af_aderivative.o
47 48
 OBJS-$(CONFIG_AINTERLEAVE_FILTER)            += f_interleave.o
48 49
 OBJS-$(CONFIG_ALIMITER_FILTER)               += af_alimiter.o
49 50
 OBJS-$(CONFIG_ALLPASS_FILTER)                += af_biquads.o
50 51
new file mode 100644
... ...
@@ -0,0 +1,207 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include "audio.h"
19
+#include "avfilter.h"
20
+#include "internal.h"
21
+
22
+typedef struct ADerivativeContext {
23
+    const AVClass *class;
24
+    AVFrame *prev;
25
+    void (*filter)(void **dst, void **prv, const void **src,
26
+                   int nb_samples, int channels);
27
+} ADerivativeContext;
28
+
29
+static int query_formats(AVFilterContext *ctx)
30
+{
31
+    AVFilterFormats *formats = NULL;
32
+    AVFilterChannelLayouts *layouts = NULL;
33
+    static const enum AVSampleFormat derivative_sample_fmts[] = {
34
+        AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLTP,
35
+        AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_DBLP,
36
+        AV_SAMPLE_FMT_NONE
37
+    };
38
+    static const enum AVSampleFormat integral_sample_fmts[] = {
39
+        AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
40
+        AV_SAMPLE_FMT_NONE
41
+    };
42
+    int ret;
43
+
44
+    formats = ff_make_format_list(strcmp(ctx->filter->name, "aintegral") ?
45
+                                  derivative_sample_fmts : integral_sample_fmts);
46
+    if (!formats)
47
+        return AVERROR(ENOMEM);
48
+    ret = ff_set_common_formats(ctx, formats);
49
+    if (ret < 0)
50
+        return ret;
51
+
52
+    layouts = ff_all_channel_counts();
53
+    if (!layouts)
54
+        return AVERROR(ENOMEM);
55
+
56
+    ret = ff_set_common_channel_layouts(ctx, layouts);
57
+    if (ret < 0)
58
+        return ret;
59
+
60
+    formats = ff_all_samplerates();
61
+    return ff_set_common_samplerates(ctx, formats);
62
+}
63
+
64
+#define DERIVATIVE(name, type)                                          \
65
+static void aderivative_## name ##p(void **d, void **p, const void **s, \
66
+                                    int nb_samples, int channels)       \
67
+{                                                                       \
68
+    int n, c;                                                           \
69
+                                                                        \
70
+    for (c = 0; c < channels; c++) {                                    \
71
+        const type *src = s[c];                                         \
72
+        type *dst = d[c];                                               \
73
+        type *prv = p[c];                                               \
74
+                                                                        \
75
+        for (n = 0; n < nb_samples; n++) {                              \
76
+            const type current = src[n];                                \
77
+                                                                        \
78
+            dst[n] = current - prv[0];                                  \
79
+            prv[0] = current;                                           \
80
+        }                                                               \
81
+    }                                                                   \
82
+}
83
+
84
+DERIVATIVE(flt, float)
85
+DERIVATIVE(dbl, double)
86
+DERIVATIVE(s16, int16_t)
87
+DERIVATIVE(s32, int32_t)
88
+
89
+#define INTEGRAL(name, type)                                          \
90
+static void aintegral_## name ##p(void **d, void **p, const void **s, \
91
+                                  int nb_samples, int channels)       \
92
+{                                                                     \
93
+    int n, c;                                                         \
94
+                                                                      \
95
+    for (c = 0; c < channels; c++) {                                  \
96
+        const type *src = s[c];                                       \
97
+        type *dst = d[c];                                             \
98
+        type *prv = p[c];                                             \
99
+                                                                      \
100
+        for (n = 0; n < nb_samples; n++) {                            \
101
+            const type current = src[n];                              \
102
+                                                                      \
103
+            dst[n] = current + prv[0];                                \
104
+            prv[0] = dst[n];                                          \
105
+        }                                                             \
106
+    }                                                                 \
107
+}
108
+
109
+INTEGRAL(flt, float)
110
+INTEGRAL(dbl, double)
111
+
112
+static int config_input(AVFilterLink *inlink)
113
+{
114
+    AVFilterContext *ctx = inlink->dst;
115
+    ADerivativeContext *s = ctx->priv;
116
+
117
+    switch (inlink->format) {
118
+    case AV_SAMPLE_FMT_FLTP: s->filter = aderivative_fltp; break;
119
+    case AV_SAMPLE_FMT_DBLP: s->filter = aderivative_dblp; break;
120
+    case AV_SAMPLE_FMT_S32P: s->filter = aderivative_s32p; break;
121
+    case AV_SAMPLE_FMT_S16P: s->filter = aderivative_s16p; break;
122
+    }
123
+
124
+    if (strcmp(ctx->filter->name, "aintegral"))
125
+        return 0;
126
+
127
+    switch (inlink->format) {
128
+    case AV_SAMPLE_FMT_FLTP: s->filter = aintegral_fltp; break;
129
+    case AV_SAMPLE_FMT_DBLP: s->filter = aintegral_dblp; break;
130
+    }
131
+
132
+    return 0;
133
+}
134
+
135
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
136
+{
137
+    AVFilterContext *ctx = inlink->dst;
138
+    ADerivativeContext *s = ctx->priv;
139
+    AVFilterLink *outlink = ctx->outputs[0];
140
+    AVFrame *out = ff_get_audio_buffer(outlink, in->nb_samples);
141
+
142
+    if (!out) {
143
+        av_frame_free(&in);
144
+        return AVERROR(ENOMEM);
145
+    }
146
+    av_frame_copy_props(out, in);
147
+
148
+    if (!s->prev) {
149
+        s->prev = ff_get_audio_buffer(inlink, 1);
150
+        if (!s->prev) {
151
+            av_frame_free(&in);
152
+            return AVERROR(ENOMEM);
153
+        }
154
+    }
155
+
156
+    s->filter((void **)out->extended_data, (void **)s->prev->extended_data, (const void **)in->extended_data,
157
+              in->nb_samples, in->channels);
158
+
159
+    av_frame_free(&in);
160
+    return ff_filter_frame(outlink, out);
161
+}
162
+
163
+static av_cold void uninit(AVFilterContext *ctx)
164
+{
165
+    ADerivativeContext *s = ctx->priv;
166
+
167
+    av_frame_free(&s->prev);
168
+}
169
+
170
+static const AVFilterPad aderivative_inputs[] = {
171
+    {
172
+        .name         = "default",
173
+        .type         = AVMEDIA_TYPE_AUDIO,
174
+        .filter_frame = filter_frame,
175
+        .config_props = config_input,
176
+    },
177
+    { NULL }
178
+};
179
+
180
+static const AVFilterPad aderivative_outputs[] = {
181
+    {
182
+        .name = "default",
183
+        .type = AVMEDIA_TYPE_AUDIO,
184
+    },
185
+    { NULL }
186
+};
187
+
188
+AVFilter ff_af_aderivative = {
189
+    .name          = "aderivative",
190
+    .description   = NULL_IF_CONFIG_SMALL("Compute derivative of input audio."),
191
+    .query_formats = query_formats,
192
+    .priv_size     = sizeof(ADerivativeContext),
193
+    .uninit        = uninit,
194
+    .inputs        = aderivative_inputs,
195
+    .outputs       = aderivative_outputs,
196
+};
197
+
198
+AVFilter ff_af_aintegral = {
199
+    .name          = "aintegral",
200
+    .description   = NULL_IF_CONFIG_SMALL("Compute integral of input audio."),
201
+    .query_formats = query_formats,
202
+    .priv_size     = sizeof(ADerivativeContext),
203
+    .uninit        = uninit,
204
+    .inputs        = aderivative_inputs,
205
+    .outputs       = aderivative_outputs,
206
+};
... ...
@@ -30,6 +30,7 @@ extern AVFilter ff_af_acopy;
30 30
 extern AVFilter ff_af_acrossfade;
31 31
 extern AVFilter ff_af_acrusher;
32 32
 extern AVFilter ff_af_adelay;
33
+extern AVFilter ff_af_aderivative;
33 34
 extern AVFilter ff_af_aecho;
34 35
 extern AVFilter ff_af_aemphasis;
35 36
 extern AVFilter ff_af_aeval;
... ...
@@ -39,6 +40,7 @@ extern AVFilter ff_af_afir;
39 39
 extern AVFilter ff_af_aformat;
40 40
 extern AVFilter ff_af_agate;
41 41
 extern AVFilter ff_af_aiir;
42
+extern AVFilter ff_af_aintegral;
42 43
 extern AVFilter ff_af_ainterleave;
43 44
 extern AVFilter ff_af_alimiter;
44 45
 extern AVFilter ff_af_allpass;
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR   7
33
-#define LIBAVFILTER_VERSION_MINOR  22
33
+#define LIBAVFILTER_VERSION_MINOR  23
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \