• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "libavutil/opt.h"
20 #include "audio.h"
21 #include "avfilter.h"
22 #include "internal.h"
23 
24 typedef struct ADerivativeContext {
25     const AVClass *class;
26     AVFrame *prev;
27     void (*filter)(void **dst, void **prv, const void **src,
28                    int nb_samples, int channels);
29 } ADerivativeContext;
30 
31 #define DERIVATIVE(name, type)                                          \
32 static void aderivative_## name ##p(void **d, void **p, const void **s, \
33                                     int nb_samples, int channels)       \
34 {                                                                       \
35     int n, c;                                                           \
36                                                                         \
37     for (c = 0; c < channels; c++) {                                    \
38         const type *src = s[c];                                         \
39         type *dst = d[c];                                               \
40         type *prv = p[c];                                               \
41                                                                         \
42         for (n = 0; n < nb_samples; n++) {                              \
43             const type current = src[n];                                \
44                                                                         \
45             dst[n] = current - prv[0];                                  \
46             prv[0] = current;                                           \
47         }                                                               \
48     }                                                                   \
49 }
50 
DERIVATIVE(flt,float)51 DERIVATIVE(flt, float)
52 DERIVATIVE(dbl, double)
53 DERIVATIVE(s16, int16_t)
54 DERIVATIVE(s32, int32_t)
55 
56 #define INTEGRAL(name, type)                                          \
57 static void aintegral_## name ##p(void **d, void **p, const void **s, \
58                                   int nb_samples, int channels)       \
59 {                                                                     \
60     int n, c;                                                         \
61                                                                       \
62     for (c = 0; c < channels; c++) {                                  \
63         const type *src = s[c];                                       \
64         type *dst = d[c];                                             \
65         type *prv = p[c];                                             \
66                                                                       \
67         for (n = 0; n < nb_samples; n++) {                            \
68             const type current = src[n];                              \
69                                                                       \
70             dst[n] = current + prv[0];                                \
71             prv[0] = dst[n];                                          \
72         }                                                             \
73     }                                                                 \
74 }
75 
76 INTEGRAL(flt, float)
77 INTEGRAL(dbl, double)
78 
79 static int config_input(AVFilterLink *inlink)
80 {
81     AVFilterContext *ctx = inlink->dst;
82     ADerivativeContext *s = ctx->priv;
83 
84     switch (inlink->format) {
85     case AV_SAMPLE_FMT_FLTP: s->filter = aderivative_fltp; break;
86     case AV_SAMPLE_FMT_DBLP: s->filter = aderivative_dblp; break;
87     case AV_SAMPLE_FMT_S32P: s->filter = aderivative_s32p; break;
88     case AV_SAMPLE_FMT_S16P: s->filter = aderivative_s16p; break;
89     }
90 
91     if (strcmp(ctx->filter->name, "aintegral"))
92         return 0;
93 
94     switch (inlink->format) {
95     case AV_SAMPLE_FMT_FLTP: s->filter = aintegral_fltp; break;
96     case AV_SAMPLE_FMT_DBLP: s->filter = aintegral_dblp; break;
97     }
98 
99     return 0;
100 }
101 
filter_frame(AVFilterLink * inlink,AVFrame * in)102 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
103 {
104     AVFilterContext *ctx = inlink->dst;
105     ADerivativeContext *s = ctx->priv;
106     AVFilterLink *outlink = ctx->outputs[0];
107     AVFrame *out;
108 
109     if (ctx->is_disabled) {
110         if (s->prev)
111             av_samples_set_silence(s->prev->extended_data, 0, 1,
112                                    s->prev->ch_layout.nb_channels,
113                                    s->prev->format);
114 
115         return ff_filter_frame(outlink, in);
116     }
117 
118     out = ff_get_audio_buffer(outlink, in->nb_samples);
119     if (!out) {
120         av_frame_free(&in);
121         return AVERROR(ENOMEM);
122     }
123     av_frame_copy_props(out, in);
124 
125     if (!s->prev) {
126         s->prev = ff_get_audio_buffer(inlink, 1);
127         if (!s->prev) {
128             av_frame_free(&in);
129             return AVERROR(ENOMEM);
130         }
131     }
132 
133     s->filter((void **)out->extended_data, (void **)s->prev->extended_data, (const void **)in->extended_data,
134               in->nb_samples, in->ch_layout.nb_channels);
135 
136     av_frame_free(&in);
137     return ff_filter_frame(outlink, out);
138 }
139 
uninit(AVFilterContext * ctx)140 static av_cold void uninit(AVFilterContext *ctx)
141 {
142     ADerivativeContext *s = ctx->priv;
143 
144     av_frame_free(&s->prev);
145 }
146 
147 static const AVFilterPad aderivative_inputs[] = {
148     {
149         .name         = "default",
150         .type         = AVMEDIA_TYPE_AUDIO,
151         .filter_frame = filter_frame,
152         .config_props = config_input,
153     },
154 };
155 
156 static const AVFilterPad aderivative_outputs[] = {
157     {
158         .name = "default",
159         .type = AVMEDIA_TYPE_AUDIO,
160     },
161 };
162 
163 static const AVOption aderivative_options[] = {
164     { NULL }
165 };
166 
167 AVFILTER_DEFINE_CLASS_EXT(aderivative, "aderivative/aintegral", aderivative_options);
168 
169 const AVFilter ff_af_aderivative = {
170     .name          = "aderivative",
171     .description   = NULL_IF_CONFIG_SMALL("Compute derivative of input audio."),
172     .priv_size     = sizeof(ADerivativeContext),
173     .priv_class    = &aderivative_class,
174     .uninit        = uninit,
175     FILTER_INPUTS(aderivative_inputs),
176     FILTER_OUTPUTS(aderivative_outputs),
177     FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLTP,
178                       AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_DBLP),
179     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
180 };
181 
182 const AVFilter ff_af_aintegral = {
183     .name          = "aintegral",
184     .description   = NULL_IF_CONFIG_SMALL("Compute integral of input audio."),
185     .priv_size     = sizeof(ADerivativeContext),
186     .priv_class    = &aderivative_class,
187     .uninit        = uninit,
188     FILTER_INPUTS(aderivative_inputs),
189     FILTER_OUTPUTS(aderivative_outputs),
190     FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP),
191     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
192 };
193