avfilter/af_silenceremove: prefer outlink instead of inlink
[ffmpeg.git] / libavfilter / af_aderivative.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include "audio.h"
20 #include "avfilter.h"
21 #include "internal.h"
22
23 typedef struct ADerivativeContext {
24     const AVClass *class;
25     AVFrame *prev;
26     void (*filter)(void **dst, void **prv, const void **src,
27                    int nb_samples, int channels);
28 } ADerivativeContext;
29
30 static int query_formats(AVFilterContext *ctx)
31 {
32     AVFilterFormats *formats = NULL;
33     AVFilterChannelLayouts *layouts = NULL;
34     static const enum AVSampleFormat derivative_sample_fmts[] = {
35         AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLTP,
36         AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_DBLP,
37         AV_SAMPLE_FMT_NONE
38     };
39     static const enum AVSampleFormat integral_sample_fmts[] = {
40         AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
41         AV_SAMPLE_FMT_NONE
42     };
43     int ret;
44
45     formats = ff_make_format_list(strcmp(ctx->filter->name, "aintegral") ?
46                                   derivative_sample_fmts : integral_sample_fmts);
47     if (!formats)
48         return AVERROR(ENOMEM);
49     ret = ff_set_common_formats(ctx, formats);
50     if (ret < 0)
51         return ret;
52
53     layouts = ff_all_channel_counts();
54     if (!layouts)
55         return AVERROR(ENOMEM);
56
57     ret = ff_set_common_channel_layouts(ctx, layouts);
58     if (ret < 0)
59         return ret;
60
61     formats = ff_all_samplerates();
62     return ff_set_common_samplerates(ctx, formats);
63 }
64
65 #define DERIVATIVE(name, type)                                          \
66 static void aderivative_## name ##p(void **d, void **p, const void **s, \
67                                     int nb_samples, int channels)       \
68 {                                                                       \
69     int n, c;                                                           \
70                                                                         \
71     for (c = 0; c < channels; c++) {                                    \
72         const type *src = s[c];                                         \
73         type *dst = d[c];                                               \
74         type *prv = p[c];                                               \
75                                                                         \
76         for (n = 0; n < nb_samples; n++) {                              \
77             const type current = src[n];                                \
78                                                                         \
79             dst[n] = current - prv[0];                                  \
80             prv[0] = current;                                           \
81         }                                                               \
82     }                                                                   \
83 }
84
85 DERIVATIVE(flt, float)
86 DERIVATIVE(dbl, double)
87 DERIVATIVE(s16, int16_t)
88 DERIVATIVE(s32, int32_t)
89
90 #define INTEGRAL(name, type)                                          \
91 static void aintegral_## name ##p(void **d, void **p, const void **s, \
92                                   int nb_samples, int channels)       \
93 {                                                                     \
94     int n, c;                                                         \
95                                                                       \
96     for (c = 0; c < channels; c++) {                                  \
97         const type *src = s[c];                                       \
98         type *dst = d[c];                                             \
99         type *prv = p[c];                                             \
100                                                                       \
101         for (n = 0; n < nb_samples; n++) {                            \
102             const type current = src[n];                              \
103                                                                       \
104             dst[n] = current + prv[0];                                \
105             prv[0] = dst[n];                                          \
106         }                                                             \
107     }                                                                 \
108 }
109
110 INTEGRAL(flt, float)
111 INTEGRAL(dbl, double)
112
113 static int config_input(AVFilterLink *inlink)
114 {
115     AVFilterContext *ctx = inlink->dst;
116     ADerivativeContext *s = ctx->priv;
117
118     switch (inlink->format) {
119     case AV_SAMPLE_FMT_FLTP: s->filter = aderivative_fltp; break;
120     case AV_SAMPLE_FMT_DBLP: s->filter = aderivative_dblp; break;
121     case AV_SAMPLE_FMT_S32P: s->filter = aderivative_s32p; break;
122     case AV_SAMPLE_FMT_S16P: s->filter = aderivative_s16p; break;
123     }
124
125     if (strcmp(ctx->filter->name, "aintegral"))
126         return 0;
127
128     switch (inlink->format) {
129     case AV_SAMPLE_FMT_FLTP: s->filter = aintegral_fltp; break;
130     case AV_SAMPLE_FMT_DBLP: s->filter = aintegral_dblp; break;
131     }
132
133     return 0;
134 }
135
136 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
137 {
138     AVFilterContext *ctx = inlink->dst;
139     ADerivativeContext *s = ctx->priv;
140     AVFilterLink *outlink = ctx->outputs[0];
141     AVFrame *out = ff_get_audio_buffer(outlink, in->nb_samples);
142
143     if (!out) {
144         av_frame_free(&in);
145         return AVERROR(ENOMEM);
146     }
147     av_frame_copy_props(out, in);
148
149     if (!s->prev) {
150         s->prev = ff_get_audio_buffer(inlink, 1);
151         if (!s->prev) {
152             av_frame_free(&in);
153             return AVERROR(ENOMEM);
154         }
155     }
156
157     s->filter((void **)out->extended_data, (void **)s->prev->extended_data, (const void **)in->extended_data,
158               in->nb_samples, in->channels);
159
160     av_frame_free(&in);
161     return ff_filter_frame(outlink, out);
162 }
163
164 static av_cold void uninit(AVFilterContext *ctx)
165 {
166     ADerivativeContext *s = ctx->priv;
167
168     av_frame_free(&s->prev);
169 }
170
171 static const AVFilterPad aderivative_inputs[] = {
172     {
173         .name         = "default",
174         .type         = AVMEDIA_TYPE_AUDIO,
175         .filter_frame = filter_frame,
176         .config_props = config_input,
177     },
178     { NULL }
179 };
180
181 static const AVFilterPad aderivative_outputs[] = {
182     {
183         .name = "default",
184         .type = AVMEDIA_TYPE_AUDIO,
185     },
186     { NULL }
187 };
188
189 AVFilter ff_af_aderivative = {
190     .name          = "aderivative",
191     .description   = NULL_IF_CONFIG_SMALL("Compute derivative of input audio."),
192     .query_formats = query_formats,
193     .priv_size     = sizeof(ADerivativeContext),
194     .uninit        = uninit,
195     .inputs        = aderivative_inputs,
196     .outputs       = aderivative_outputs,
197 };
198
199 AVFilter ff_af_aintegral = {
200     .name          = "aintegral",
201     .description   = NULL_IF_CONFIG_SMALL("Compute integral of input audio."),
202     .query_formats = query_formats,
203     .priv_size     = sizeof(ADerivativeContext),
204     .uninit        = uninit,
205     .inputs        = aderivative_inputs,
206     .outputs       = aderivative_outputs,
207 };