GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavfilter/af_adenorm.c Lines: 0 141 0.0 %
Date: 2020-11-28 20:53:16 Branches: 0 65 0.0 %

Line Branch Exec Source
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
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
};