]> git.sesse.net Git - ffmpeg/blob - libavfilter/af_adenorm.c
avfilter: Constify all AVFilters
[ffmpeg] / libavfilter / af_adenorm.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 "libavutil/avassert.h"
20 #include "libavutil/channel_layout.h"
21 #include "libavutil/opt.h"
22 #include "audio.h"
23 #include "avfilter.h"
24 #include "internal.h"
25
26 enum FilterType {
27     DC_TYPE,
28     AC_TYPE,
29     SQ_TYPE,
30     PS_TYPE,
31     NB_TYPES,
32 };
33
34 typedef struct ADenormContext {
35     const AVClass *class;
36
37     double level;
38     double level_db;
39     int type;
40     int64_t in_samples;
41
42     void (*filter)(AVFilterContext *ctx, void *dst,
43                    const void *src, int nb_samples);
44 } ADenormContext;
45
46 static int query_formats(AVFilterContext *ctx)
47 {
48     AVFilterFormats *formats = NULL;
49     AVFilterChannelLayouts *layouts = NULL;
50     static const enum AVSampleFormat sample_fmts[] = {
51         AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
52         AV_SAMPLE_FMT_NONE
53     };
54     int ret;
55
56     formats = ff_make_format_list(sample_fmts);
57     if (!formats)
58         return AVERROR(ENOMEM);
59     ret = ff_set_common_formats(ctx, formats);
60     if (ret < 0)
61         return ret;
62
63     layouts = ff_all_channel_counts();
64     if (!layouts)
65         return AVERROR(ENOMEM);
66
67     ret = ff_set_common_channel_layouts(ctx, layouts);
68     if (ret < 0)
69         return ret;
70
71     formats = ff_all_samplerates();
72     return ff_set_common_samplerates(ctx, formats);
73 }
74
75 static void dc_denorm_fltp(AVFilterContext *ctx, void *dstp,
76                            const void *srcp, int nb_samples)
77 {
78     ADenormContext *s = ctx->priv;
79     const float *src = (const float *)srcp;
80     float *dst = (float *)dstp;
81     const float dc = s->level;
82
83     for (int n = 0; n < nb_samples; n++) {
84         dst[n] = src[n] + dc;
85     }
86 }
87
88 static void dc_denorm_dblp(AVFilterContext *ctx, void *dstp,
89                            const void *srcp, int nb_samples)
90 {
91     ADenormContext *s = ctx->priv;
92     const double *src = (const double *)srcp;
93     double *dst = (double *)dstp;
94     const double dc = s->level;
95
96     for (int n = 0; n < nb_samples; n++) {
97         dst[n] = src[n] + dc;
98     }
99 }
100
101 static void ac_denorm_fltp(AVFilterContext *ctx, void *dstp,
102                            const void *srcp, int nb_samples)
103 {
104     ADenormContext *s = ctx->priv;
105     const float *src = (const float *)srcp;
106     float *dst = (float *)dstp;
107     const float dc = s->level;
108     const int64_t N = s->in_samples;
109
110     for (int n = 0; n < nb_samples; n++) {
111         dst[n] = src[n] + dc * (((N + n) & 1) ? -1.f : 1.f);
112     }
113 }
114
115 static void ac_denorm_dblp(AVFilterContext *ctx, void *dstp,
116                            const void *srcp, int nb_samples)
117 {
118     ADenormContext *s = ctx->priv;
119     const double *src = (const double *)srcp;
120     double *dst = (double *)dstp;
121     const double dc = s->level;
122     const int64_t N = s->in_samples;
123
124     for (int n = 0; n < nb_samples; n++) {
125         dst[n] = src[n] + dc * (((N + n) & 1) ? -1. : 1.);
126     }
127 }
128
129 static void sq_denorm_fltp(AVFilterContext *ctx, void *dstp,
130                            const void *srcp, int nb_samples)
131 {
132     ADenormContext *s = ctx->priv;
133     const float *src = (const float *)srcp;
134     float *dst = (float *)dstp;
135     const float dc = s->level;
136     const int64_t N = s->in_samples;
137
138     for (int n = 0; n < nb_samples; n++) {
139         dst[n] = src[n] + dc * ((((N + n) >> 8) & 1) ? -1.f : 1.f);
140     }
141 }
142
143 static void sq_denorm_dblp(AVFilterContext *ctx, void *dstp,
144                            const void *srcp, int nb_samples)
145 {
146     ADenormContext *s = ctx->priv;
147     const double *src = (const double *)srcp;
148     double *dst = (double *)dstp;
149     const double dc = s->level;
150     const int64_t N = s->in_samples;
151
152     for (int n = 0; n < nb_samples; n++) {
153         dst[n] = src[n] + dc * ((((N + n) >> 8) & 1) ? -1. : 1.);
154     }
155 }
156
157 static void ps_denorm_fltp(AVFilterContext *ctx, void *dstp,
158                            const void *srcp, int nb_samples)
159 {
160     ADenormContext *s = ctx->priv;
161     const float *src = (const float *)srcp;
162     float *dst = (float *)dstp;
163     const float dc = s->level;
164     const int64_t N = s->in_samples;
165
166     for (int n = 0; n < nb_samples; n++) {
167         dst[n] = src[n] + dc * (((N + n) & 255) ? 0.f : 1.f);
168     }
169 }
170
171 static void ps_denorm_dblp(AVFilterContext *ctx, void *dstp,
172                            const void *srcp, int nb_samples)
173 {
174     ADenormContext *s = ctx->priv;
175     const double *src = (const double *)srcp;
176     double *dst = (double *)dstp;
177     const double dc = s->level;
178     const int64_t N = s->in_samples;
179
180     for (int n = 0; n < nb_samples; n++) {
181         dst[n] = src[n] + dc * (((N + n) & 255) ? 0. : 1.);
182     }
183 }
184
185 static int config_output(AVFilterLink *outlink)
186 {
187     AVFilterContext *ctx = outlink->src;
188     ADenormContext *s = ctx->priv;
189
190     switch (s->type) {
191     case DC_TYPE:
192         switch (outlink->format) {
193         case AV_SAMPLE_FMT_FLTP: s->filter = dc_denorm_fltp; break;
194         case AV_SAMPLE_FMT_DBLP: s->filter = dc_denorm_dblp; break;
195         }
196         break;
197     case AC_TYPE:
198         switch (outlink->format) {
199         case AV_SAMPLE_FMT_FLTP: s->filter = ac_denorm_fltp; break;
200         case AV_SAMPLE_FMT_DBLP: s->filter = ac_denorm_dblp; break;
201         }
202         break;
203     case SQ_TYPE:
204         switch (outlink->format) {
205         case AV_SAMPLE_FMT_FLTP: s->filter = sq_denorm_fltp; break;
206         case AV_SAMPLE_FMT_DBLP: s->filter = sq_denorm_dblp; break;
207         }
208         break;
209     case PS_TYPE:
210         switch (outlink->format) {
211         case AV_SAMPLE_FMT_FLTP: s->filter = ps_denorm_fltp; break;
212         case AV_SAMPLE_FMT_DBLP: s->filter = ps_denorm_dblp; break;
213         }
214         break;
215     default:
216         av_assert0(0);
217     }
218
219     return 0;
220 }
221
222 typedef struct ThreadData {
223     AVFrame *in, *out;
224 } ThreadData;
225
226 static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
227 {
228     ADenormContext *s = ctx->priv;
229     ThreadData *td = arg;
230     AVFrame *out = td->out;
231     AVFrame *in = td->in;
232     const int start = (in->channels * jobnr) / nb_jobs;
233     const int end = (in->channels * (jobnr+1)) / nb_jobs;
234
235     for (int ch = start; ch < end; ch++) {
236         s->filter(ctx, out->extended_data[ch],
237                   in->extended_data[ch],
238                   in->nb_samples);
239     }
240
241     return 0;
242 }
243
244 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
245 {
246     AVFilterContext *ctx = inlink->dst;
247     ADenormContext *s = ctx->priv;
248     AVFilterLink *outlink = ctx->outputs[0];
249     ThreadData td;
250     AVFrame *out;
251
252     if (av_frame_is_writable(in)) {
253         out = in;
254     } else {
255         out = ff_get_audio_buffer(outlink, in->nb_samples);
256         if (!out) {
257             av_frame_free(&in);
258             return AVERROR(ENOMEM);
259         }
260         av_frame_copy_props(out, in);
261     }
262
263     s->level = exp(s->level_db / 20. * M_LN10);
264     td.in = in; td.out = out;
265     ctx->internal->execute(ctx, filter_channels, &td, NULL, FFMIN(inlink->channels,
266                                                             ff_filter_get_nb_threads(ctx)));
267
268     s->in_samples += in->nb_samples;
269
270     if (out != in)
271         av_frame_free(&in);
272     return ff_filter_frame(outlink, out);
273 }
274
275 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
276                            char *res, int res_len, int flags)
277 {
278     AVFilterLink *outlink = ctx->outputs[0];
279     int ret;
280
281     ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
282     if (ret < 0)
283         return ret;
284
285     return config_output(outlink);
286 }
287
288 static const AVFilterPad adenorm_inputs[] = {
289     {
290         .name         = "default",
291         .type         = AVMEDIA_TYPE_AUDIO,
292         .filter_frame = filter_frame,
293     },
294     { NULL }
295 };
296
297 static const AVFilterPad adenorm_outputs[] = {
298     {
299         .name         = "default",
300         .type         = AVMEDIA_TYPE_AUDIO,
301         .config_props = config_output,
302     },
303     { NULL }
304 };
305
306 #define OFFSET(x) offsetof(ADenormContext, x)
307 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
308
309 static const AVOption adenorm_options[] = {
310     { "level", "set level", OFFSET(level_db), AV_OPT_TYPE_DOUBLE, {.dbl=-351},   -451,        -90, FLAGS },
311     { "type",  "set type",  OFFSET(type),     AV_OPT_TYPE_INT,    {.i64=DC_TYPE},   0, NB_TYPES-1, FLAGS, "type" },
312     { "dc",    NULL,  0, AV_OPT_TYPE_CONST, {.i64=DC_TYPE}, 0, 0, FLAGS, "type"},
313     { "ac",    NULL,  0, AV_OPT_TYPE_CONST, {.i64=AC_TYPE}, 0, 0, FLAGS, "type"},
314     { "square",NULL,  0, AV_OPT_TYPE_CONST, {.i64=SQ_TYPE}, 0, 0, FLAGS, "type"},
315     { "pulse", NULL,  0, AV_OPT_TYPE_CONST, {.i64=PS_TYPE}, 0, 0, FLAGS, "type"},
316     { NULL }
317 };
318
319 AVFILTER_DEFINE_CLASS(adenorm);
320
321 const AVFilter ff_af_adenorm = {
322     .name            = "adenorm",
323     .description     = NULL_IF_CONFIG_SMALL("Remedy denormals by adding extremely low-level noise."),
324     .query_formats   = query_formats,
325     .priv_size       = sizeof(ADenormContext),
326     .inputs          = adenorm_inputs,
327     .outputs         = adenorm_outputs,
328     .priv_class      = &adenorm_class,
329     .process_command = process_command,
330     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC |
331                        AVFILTER_FLAG_SLICE_THREADS,
332 };