GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavfilter/af_aphaser.c Lines: 0 77 0.0 %
Date: 2020-09-25 23:16:12 Branches: 0 123 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 2013 Paul B Mahol
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
/**
22
 * @file
23
 * phaser audio filter
24
 */
25
26
#include "libavutil/avassert.h"
27
#include "libavutil/opt.h"
28
#include "audio.h"
29
#include "avfilter.h"
30
#include "internal.h"
31
#include "generate_wave_table.h"
32
33
typedef struct AudioPhaserContext {
34
    const AVClass *class;
35
    double in_gain, out_gain;
36
    double delay;
37
    double decay;
38
    double speed;
39
40
    int type;
41
42
    int delay_buffer_length;
43
    double *delay_buffer;
44
45
    int modulation_buffer_length;
46
    int32_t *modulation_buffer;
47
48
    int delay_pos, modulation_pos;
49
50
    void (*phaser)(struct AudioPhaserContext *s,
51
                   uint8_t * const *src, uint8_t **dst,
52
                   int nb_samples, int channels);
53
} AudioPhaserContext;
54
55
#define OFFSET(x) offsetof(AudioPhaserContext, x)
56
#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
57
58
static const AVOption aphaser_options[] = {
59
    { "in_gain",  "set input gain",            OFFSET(in_gain),  AV_OPT_TYPE_DOUBLE, {.dbl=.4},  0,  1,   FLAGS },
60
    { "out_gain", "set output gain",           OFFSET(out_gain), AV_OPT_TYPE_DOUBLE, {.dbl=.74}, 0,  1e9, FLAGS },
61
    { "delay",    "set delay in milliseconds", OFFSET(delay),    AV_OPT_TYPE_DOUBLE, {.dbl=3.},  0,  5,   FLAGS },
62
    { "decay",    "set decay",                 OFFSET(decay),    AV_OPT_TYPE_DOUBLE, {.dbl=.4},  0, .99,  FLAGS },
63
    { "speed",    "set modulation speed",      OFFSET(speed),    AV_OPT_TYPE_DOUBLE, {.dbl=.5}, .1,  2,   FLAGS },
64
    { "type",     "set modulation type",       OFFSET(type),     AV_OPT_TYPE_INT,    {.i64=WAVE_TRI}, 0, WAVE_NB-1, FLAGS, "type" },
65
    { "triangular",  NULL, 0, AV_OPT_TYPE_CONST,  {.i64=WAVE_TRI}, 0, 0, FLAGS, "type" },
66
    { "t",           NULL, 0, AV_OPT_TYPE_CONST,  {.i64=WAVE_TRI}, 0, 0, FLAGS, "type" },
67
    { "sinusoidal",  NULL, 0, AV_OPT_TYPE_CONST,  {.i64=WAVE_SIN}, 0, 0, FLAGS, "type" },
68
    { "s",           NULL, 0, AV_OPT_TYPE_CONST,  {.i64=WAVE_SIN}, 0, 0, FLAGS, "type" },
69
    { NULL }
70
};
71
72
AVFILTER_DEFINE_CLASS(aphaser);
73
74
static av_cold int init(AVFilterContext *ctx)
75
{
76
    AudioPhaserContext *s = ctx->priv;
77
78
    if (s->in_gain > (1 - s->decay * s->decay))
79
        av_log(ctx, AV_LOG_WARNING, "in_gain may cause clipping\n");
80
    if (s->in_gain / (1 - s->decay) > 1 / s->out_gain)
81
        av_log(ctx, AV_LOG_WARNING, "out_gain may cause clipping\n");
82
83
    return 0;
84
}
85
86
static int query_formats(AVFilterContext *ctx)
87
{
88
    AVFilterFormats *formats;
89
    AVFilterChannelLayouts *layouts;
90
    static const enum AVSampleFormat sample_fmts[] = {
91
        AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
92
        AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
93
        AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
94
        AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
95
        AV_SAMPLE_FMT_NONE
96
    };
97
    int ret;
98
99
    layouts = ff_all_channel_counts();
100
    if (!layouts)
101
        return AVERROR(ENOMEM);
102
    ret = ff_set_common_channel_layouts(ctx, layouts);
103
    if (ret < 0)
104
        return ret;
105
106
    formats = ff_make_format_list(sample_fmts);
107
    if (!formats)
108
        return AVERROR(ENOMEM);
109
    ret = ff_set_common_formats(ctx, formats);
110
    if (ret < 0)
111
        return ret;
112
113
    formats = ff_all_samplerates();
114
    if (!formats)
115
        return AVERROR(ENOMEM);
116
    return ff_set_common_samplerates(ctx, formats);
117
}
118
119
#define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a))
120
121
#define PHASER_PLANAR(name, type)                                      \
122
static void phaser_## name ##p(AudioPhaserContext *s,                  \
123
                               uint8_t * const *ssrc, uint8_t **ddst,  \
124
                               int nb_samples, int channels)           \
125
{                                                                      \
126
    int i, c, delay_pos, modulation_pos;                               \
127
                                                                       \
128
    av_assert0(channels > 0);                                          \
129
    for (c = 0; c < channels; c++) {                                   \
130
        type *src = (type *)ssrc[c];                                   \
131
        type *dst = (type *)ddst[c];                                   \
132
        double *buffer = s->delay_buffer +                             \
133
                         c * s->delay_buffer_length;                   \
134
                                                                       \
135
        delay_pos      = s->delay_pos;                                 \
136
        modulation_pos = s->modulation_pos;                            \
137
                                                                       \
138
        for (i = 0; i < nb_samples; i++, src++, dst++) {               \
139
            double v = *src * s->in_gain + buffer[                     \
140
                       MOD(delay_pos + s->modulation_buffer[           \
141
                       modulation_pos],                                \
142
                       s->delay_buffer_length)] * s->decay;            \
143
                                                                       \
144
            modulation_pos = MOD(modulation_pos + 1,                   \
145
                             s->modulation_buffer_length);             \
146
            delay_pos = MOD(delay_pos + 1, s->delay_buffer_length);    \
147
            buffer[delay_pos] = v;                                     \
148
                                                                       \
149
            *dst = v * s->out_gain;                                    \
150
        }                                                              \
151
    }                                                                  \
152
                                                                       \
153
    s->delay_pos      = delay_pos;                                     \
154
    s->modulation_pos = modulation_pos;                                \
155
}
156
157
#define PHASER(name, type)                                              \
158
static void phaser_## name (AudioPhaserContext *s,                      \
159
                            uint8_t * const *ssrc, uint8_t **ddst,      \
160
                            int nb_samples, int channels)               \
161
{                                                                       \
162
    int i, c, delay_pos, modulation_pos;                                \
163
    type *src = (type *)ssrc[0];                                        \
164
    type *dst = (type *)ddst[0];                                        \
165
    double *buffer = s->delay_buffer;                                   \
166
                                                                        \
167
    delay_pos      = s->delay_pos;                                      \
168
    modulation_pos = s->modulation_pos;                                 \
169
                                                                        \
170
    for (i = 0; i < nb_samples; i++) {                                  \
171
        int pos = MOD(delay_pos + s->modulation_buffer[modulation_pos], \
172
                      s->delay_buffer_length) * channels;               \
173
        int npos;                                                       \
174
                                                                        \
175
        delay_pos = MOD(delay_pos + 1, s->delay_buffer_length);         \
176
        npos = delay_pos * channels;                                    \
177
        for (c = 0; c < channels; c++, src++, dst++) {                  \
178
            double v = *src * s->in_gain + buffer[pos + c] * s->decay;  \
179
                                                                        \
180
            buffer[npos + c] = v;                                       \
181
                                                                        \
182
            *dst = v * s->out_gain;                                     \
183
        }                                                               \
184
                                                                        \
185
        modulation_pos = MOD(modulation_pos + 1,                        \
186
                         s->modulation_buffer_length);                  \
187
    }                                                                   \
188
                                                                        \
189
    s->delay_pos      = delay_pos;                                      \
190
    s->modulation_pos = modulation_pos;                                 \
191
}
192
193
PHASER_PLANAR(dbl, double)
194
PHASER_PLANAR(flt, float)
195
PHASER_PLANAR(s16, int16_t)
196
PHASER_PLANAR(s32, int32_t)
197
198
PHASER(dbl, double)
199
PHASER(flt, float)
200
PHASER(s16, int16_t)
201
PHASER(s32, int32_t)
202
203
static int config_output(AVFilterLink *outlink)
204
{
205
    AudioPhaserContext *s = outlink->src->priv;
206
    AVFilterLink *inlink = outlink->src->inputs[0];
207
208
    s->delay_buffer_length = s->delay * 0.001 * inlink->sample_rate + 0.5;
209
    if (s->delay_buffer_length <= 0) {
210
        av_log(outlink->src, AV_LOG_ERROR, "delay is too small\n");
211
        return AVERROR(EINVAL);
212
    }
213
    s->delay_buffer = av_calloc(s->delay_buffer_length, sizeof(*s->delay_buffer) * inlink->channels);
214
    s->modulation_buffer_length = inlink->sample_rate / s->speed + 0.5;
215
    s->modulation_buffer = av_malloc_array(s->modulation_buffer_length, sizeof(*s->modulation_buffer));
216
217
    if (!s->modulation_buffer || !s->delay_buffer)
218
        return AVERROR(ENOMEM);
219
220
    ff_generate_wave_table(s->type, AV_SAMPLE_FMT_S32,
221
                           s->modulation_buffer, s->modulation_buffer_length,
222
                           1., s->delay_buffer_length, M_PI / 2.0);
223
224
    s->delay_pos = s->modulation_pos = 0;
225
226
    switch (inlink->format) {
227
    case AV_SAMPLE_FMT_DBL:  s->phaser = phaser_dbl;  break;
228
    case AV_SAMPLE_FMT_DBLP: s->phaser = phaser_dblp; break;
229
    case AV_SAMPLE_FMT_FLT:  s->phaser = phaser_flt;  break;
230
    case AV_SAMPLE_FMT_FLTP: s->phaser = phaser_fltp; break;
231
    case AV_SAMPLE_FMT_S16:  s->phaser = phaser_s16;  break;
232
    case AV_SAMPLE_FMT_S16P: s->phaser = phaser_s16p; break;
233
    case AV_SAMPLE_FMT_S32:  s->phaser = phaser_s32;  break;
234
    case AV_SAMPLE_FMT_S32P: s->phaser = phaser_s32p; break;
235
    default: av_assert0(0);
236
    }
237
238
    return 0;
239
}
240
241
static int filter_frame(AVFilterLink *inlink, AVFrame *inbuf)
242
{
243
    AudioPhaserContext *s = inlink->dst->priv;
244
    AVFilterLink *outlink = inlink->dst->outputs[0];
245
    AVFrame *outbuf;
246
247
    if (av_frame_is_writable(inbuf)) {
248
        outbuf = inbuf;
249
    } else {
250
        outbuf = ff_get_audio_buffer(outlink, inbuf->nb_samples);
251
        if (!outbuf) {
252
            av_frame_free(&inbuf);
253
            return AVERROR(ENOMEM);
254
        }
255
        av_frame_copy_props(outbuf, inbuf);
256
    }
257
258
    s->phaser(s, inbuf->extended_data, outbuf->extended_data,
259
              outbuf->nb_samples, outbuf->channels);
260
261
    if (inbuf != outbuf)
262
        av_frame_free(&inbuf);
263
264
    return ff_filter_frame(outlink, outbuf);
265
}
266
267
static av_cold void uninit(AVFilterContext *ctx)
268
{
269
    AudioPhaserContext *s = ctx->priv;
270
271
    av_freep(&s->delay_buffer);
272
    av_freep(&s->modulation_buffer);
273
}
274
275
static const AVFilterPad aphaser_inputs[] = {
276
    {
277
        .name         = "default",
278
        .type         = AVMEDIA_TYPE_AUDIO,
279
        .filter_frame = filter_frame,
280
    },
281
    { NULL }
282
};
283
284
static const AVFilterPad aphaser_outputs[] = {
285
    {
286
        .name         = "default",
287
        .type         = AVMEDIA_TYPE_AUDIO,
288
        .config_props = config_output,
289
    },
290
    { NULL }
291
};
292
293
AVFilter ff_af_aphaser = {
294
    .name          = "aphaser",
295
    .description   = NULL_IF_CONFIG_SMALL("Add a phasing effect to the audio."),
296
    .query_formats = query_formats,
297
    .priv_size     = sizeof(AudioPhaserContext),
298
    .init          = init,
299
    .uninit        = uninit,
300
    .inputs        = aphaser_inputs,
301
    .outputs       = aphaser_outputs,
302
    .priv_class    = &aphaser_class,
303
};