2 * This file is part of FFmpeg.
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.
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.
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
19 #include "libavutil/avassert.h"
20 #include "libavutil/channel_layout.h"
21 #include "libavutil/opt.h"
34 typedef struct ADenormContext {
42 void (*filter)(AVFilterContext *ctx, void *dst,
43 const void *src, int nb_samples);
46 static int query_formats(AVFilterContext *ctx)
48 AVFilterFormats *formats = NULL;
49 AVFilterChannelLayouts *layouts = NULL;
50 static const enum AVSampleFormat sample_fmts[] = {
51 AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
56 formats = ff_make_format_list(sample_fmts);
58 return AVERROR(ENOMEM);
59 ret = ff_set_common_formats(ctx, formats);
63 layouts = ff_all_channel_counts();
65 return AVERROR(ENOMEM);
67 ret = ff_set_common_channel_layouts(ctx, layouts);
71 formats = ff_all_samplerates();
72 return ff_set_common_samplerates(ctx, formats);
75 static void dc_denorm_fltp(AVFilterContext *ctx, void *dstp,
76 const void *srcp, int nb_samples)
78 ADenormContext *s = ctx->priv;
79 const float *src = (const float *)srcp;
80 float *dst = (float *)dstp;
81 const float dc = s->level;
83 for (int n = 0; n < nb_samples; n++) {
88 static void dc_denorm_dblp(AVFilterContext *ctx, void *dstp,
89 const void *srcp, int nb_samples)
91 ADenormContext *s = ctx->priv;
92 const double *src = (const double *)srcp;
93 double *dst = (double *)dstp;
94 const double dc = s->level;
96 for (int n = 0; n < nb_samples; n++) {
101 static void ac_denorm_fltp(AVFilterContext *ctx, void *dstp,
102 const void *srcp, int nb_samples)
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;
110 for (int n = 0; n < nb_samples; n++) {
111 dst[n] = src[n] + dc * (((N + n) & 1) ? -1.f : 1.f);
115 static void ac_denorm_dblp(AVFilterContext *ctx, void *dstp,
116 const void *srcp, int nb_samples)
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;
124 for (int n = 0; n < nb_samples; n++) {
125 dst[n] = src[n] + dc * (((N + n) & 1) ? -1. : 1.);
129 static void sq_denorm_fltp(AVFilterContext *ctx, void *dstp,
130 const void *srcp, int nb_samples)
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;
138 for (int n = 0; n < nb_samples; n++) {
139 dst[n] = src[n] + dc * ((((N + n) >> 8) & 1) ? -1.f : 1.f);
143 static void sq_denorm_dblp(AVFilterContext *ctx, void *dstp,
144 const void *srcp, int nb_samples)
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;
152 for (int n = 0; n < nb_samples; n++) {
153 dst[n] = src[n] + dc * ((((N + n) >> 8) & 1) ? -1. : 1.);
157 static void ps_denorm_fltp(AVFilterContext *ctx, void *dstp,
158 const void *srcp, int nb_samples)
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;
166 for (int n = 0; n < nb_samples; n++) {
167 dst[n] = src[n] + dc * (((N + n) & 255) ? 0.f : 1.f);
171 static void ps_denorm_dblp(AVFilterContext *ctx, void *dstp,
172 const void *srcp, int nb_samples)
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;
180 for (int n = 0; n < nb_samples; n++) {
181 dst[n] = src[n] + dc * (((N + n) & 255) ? 0. : 1.);
185 static int config_output(AVFilterLink *outlink)
187 AVFilterContext *ctx = outlink->src;
188 ADenormContext *s = ctx->priv;
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;
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;
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;
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;
222 typedef struct ThreadData {
226 static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
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;
235 for (int ch = start; ch < end; ch++) {
236 s->filter(ctx, out->extended_data[ch],
237 in->extended_data[ch],
244 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
246 AVFilterContext *ctx = inlink->dst;
247 ADenormContext *s = ctx->priv;
248 AVFilterLink *outlink = ctx->outputs[0];
252 if (av_frame_is_writable(in)) {
255 out = ff_get_audio_buffer(outlink, in->nb_samples);
258 return AVERROR(ENOMEM);
260 av_frame_copy_props(out, in);
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)));
268 s->in_samples += in->nb_samples;
272 return ff_filter_frame(outlink, out);
275 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
276 char *res, int res_len, int flags)
278 AVFilterLink *outlink = ctx->outputs[0];
281 ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
285 return config_output(outlink);
288 static const AVFilterPad adenorm_inputs[] = {
291 .type = AVMEDIA_TYPE_AUDIO,
292 .filter_frame = filter_frame,
297 static const AVFilterPad adenorm_outputs[] = {
300 .type = AVMEDIA_TYPE_AUDIO,
301 .config_props = config_output,
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
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"},
319 AVFILTER_DEFINE_CLASS(adenorm);
321 AVFilter ff_af_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,