Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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
#include "libavutil/avassert.h"
23
#include "libavutil/avstring.h"
24
#include "libavutil/opt.h"
25
#include "libavutil/samplefmt.h"
26
#include "avfilter.h"
27
#include "audio.h"
28
#include "internal.h"
29
 
30
typedef struct AudioEchoContext {
31
    const AVClass *class;
32
    float in_gain, out_gain;
33
    char *delays, *decays;
34
    float *delay, *decay;
35
    int nb_echoes;
36
    int delay_index;
37
    uint8_t **delayptrs;
38
    int max_samples, fade_out;
39
    int *samples;
40
    int64_t next_pts;
41
 
42
    void (*echo_samples)(struct AudioEchoContext *ctx, uint8_t **delayptrs,
43
                         uint8_t * const *src, uint8_t **dst,
44
                         int nb_samples, int channels);
45
} AudioEchoContext;
46
 
47
#define OFFSET(x) offsetof(AudioEchoContext, x)
48
#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
49
 
50
static const AVOption aecho_options[] = {
51
    { "in_gain",  "set signal input gain",  OFFSET(in_gain),  AV_OPT_TYPE_FLOAT,  {.dbl=0.6}, 0, 1, A },
52
    { "out_gain", "set signal output gain", OFFSET(out_gain), AV_OPT_TYPE_FLOAT,  {.dbl=0.3}, 0, 1, A },
53
    { "delays",   "set list of signal delays", OFFSET(delays), AV_OPT_TYPE_STRING, {.str="1000"}, 0, 0, A },
54
    { "decays",   "set list of signal decays", OFFSET(decays), AV_OPT_TYPE_STRING, {.str="0.5"}, 0, 0, A },
55
    { NULL }
56
};
57
 
58
AVFILTER_DEFINE_CLASS(aecho);
59
 
60
static void count_items(char *item_str, int *nb_items)
61
{
62
    char *p;
63
 
64
    *nb_items = 1;
65
    for (p = item_str; *p; p++) {
66
        if (*p == '|')
67
            (*nb_items)++;
68
    }
69
 
70
}
71
 
72
static void fill_items(char *item_str, int *nb_items, float *items)
73
{
74
    char *p, *saveptr = NULL;
75
    int i, new_nb_items = 0;
76
 
77
    p = item_str;
78
    for (i = 0; i < *nb_items; i++) {
79
        char *tstr = av_strtok(p, "|", &saveptr);
80
        p = NULL;
81
        new_nb_items += sscanf(tstr, "%f", &items[i]) == 1;
82
    }
83
 
84
    *nb_items = new_nb_items;
85
}
86
 
87
static av_cold void uninit(AVFilterContext *ctx)
88
{
89
    AudioEchoContext *s = ctx->priv;
90
 
91
    av_freep(&s->delay);
92
    av_freep(&s->decay);
93
    av_freep(&s->samples);
94
 
95
    if (s->delayptrs)
96
        av_freep(&s->delayptrs[0]);
97
    av_freep(&s->delayptrs);
98
}
99
 
100
static av_cold int init(AVFilterContext *ctx)
101
{
102
    AudioEchoContext *s = ctx->priv;
103
    int nb_delays, nb_decays, i;
104
 
105
    if (!s->delays || !s->decays) {
106
        av_log(ctx, AV_LOG_ERROR, "Missing delays and/or decays.\n");
107
        return AVERROR(EINVAL);
108
    }
109
 
110
    count_items(s->delays, &nb_delays);
111
    count_items(s->decays, &nb_decays);
112
 
113
    s->delay = av_realloc_f(s->delay, nb_delays, sizeof(*s->delay));
114
    s->decay = av_realloc_f(s->decay, nb_decays, sizeof(*s->decay));
115
    if (!s->delay || !s->decay)
116
        return AVERROR(ENOMEM);
117
 
118
    fill_items(s->delays, &nb_delays, s->delay);
119
    fill_items(s->decays, &nb_decays, s->decay);
120
 
121
    if (nb_delays != nb_decays) {
122
        av_log(ctx, AV_LOG_ERROR, "Number of delays %d differs from number of decays %d.\n", nb_delays, nb_decays);
123
        return AVERROR(EINVAL);
124
    }
125
 
126
    s->nb_echoes = nb_delays;
127
    if (!s->nb_echoes) {
128
        av_log(ctx, AV_LOG_ERROR, "At least one decay & delay must be set.\n");
129
        return AVERROR(EINVAL);
130
    }
131
 
132
    s->samples = av_realloc_f(s->samples, nb_delays, sizeof(*s->samples));
133
    if (!s->samples)
134
        return AVERROR(ENOMEM);
135
 
136
    for (i = 0; i < nb_delays; i++) {
137
        if (s->delay[i] <= 0 || s->delay[i] > 90000) {
138
            av_log(ctx, AV_LOG_ERROR, "delay[%d]: %f is out of allowed range: (0, 90000]\n", i, s->delay[i]);
139
            return AVERROR(EINVAL);
140
        }
141
        if (s->decay[i] <= 0 || s->decay[i] > 1) {
142
            av_log(ctx, AV_LOG_ERROR, "decay[%d]: %f is out of allowed range: (0, 1]\n", i, s->decay[i]);
143
            return AVERROR(EINVAL);
144
        }
145
    }
146
 
147
    s->next_pts = AV_NOPTS_VALUE;
148
 
149
    av_log(ctx, AV_LOG_DEBUG, "nb_echoes:%d\n", s->nb_echoes);
150
    return 0;
151
}
152
 
153
static int query_formats(AVFilterContext *ctx)
154
{
155
    AVFilterChannelLayouts *layouts;
156
    AVFilterFormats *formats;
157
    static const enum AVSampleFormat sample_fmts[] = {
158
        AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P,
159
        AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
160
        AV_SAMPLE_FMT_NONE
161
    };
162
 
163
    layouts = ff_all_channel_layouts();
164
    if (!layouts)
165
        return AVERROR(ENOMEM);
166
    ff_set_common_channel_layouts(ctx, layouts);
167
 
168
    formats = ff_make_format_list(sample_fmts);
169
    if (!formats)
170
        return AVERROR(ENOMEM);
171
    ff_set_common_formats(ctx, formats);
172
 
173
    formats = ff_all_samplerates();
174
    if (!formats)
175
        return AVERROR(ENOMEM);
176
    ff_set_common_samplerates(ctx, formats);
177
 
178
    return 0;
179
}
180
 
181
#define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a))
182
 
183
#define ECHO(name, type, min, max)                                          \
184
static void echo_samples_## name ##p(AudioEchoContext *ctx,                 \
185
                                     uint8_t **delayptrs,                   \
186
                                     uint8_t * const *src, uint8_t **dst,   \
187
                                     int nb_samples, int channels)          \
188
{                                                                           \
189
    const double out_gain = ctx->out_gain;                                  \
190
    const double in_gain = ctx->in_gain;                                    \
191
    const int nb_echoes = ctx->nb_echoes;                                   \
192
    const int max_samples = ctx->max_samples;                               \
193
    int i, j, chan, av_uninit(index);                                       \
194
                                                                            \
195
    av_assert1(channels > 0); /* would corrupt delay_index */               \
196
                                                                            \
197
    for (chan = 0; chan < channels; chan++) {                               \
198
        const type *s = (type *)src[chan];                                  \
199
        type *d = (type *)dst[chan];                                        \
200
        type *dbuf = (type *)delayptrs[chan];                               \
201
                                                                            \
202
        index = ctx->delay_index;                                           \
203
        for (i = 0; i < nb_samples; i++, s++, d++) {                        \
204
            double out, in;                                                 \
205
                                                                            \
206
            in = *s;                                                        \
207
            out = in * in_gain;                                             \
208
            for (j = 0; j < nb_echoes; j++) {                               \
209
                int ix = index + max_samples - ctx->samples[j];             \
210
                ix = MOD(ix, max_samples);                                  \
211
                out += dbuf[ix] * ctx->decay[j];                            \
212
            }                                                               \
213
            out *= out_gain;                                                \
214
                                                                            \
215
            *d = av_clipd(out, min, max);                                   \
216
            dbuf[index] = in;                                               \
217
                                                                            \
218
            index = MOD(index + 1, max_samples);                            \
219
        }                                                                   \
220
    }                                                                       \
221
    ctx->delay_index = index;                                               \
222
}
223
 
224
ECHO(dbl, double,  -1.0,      1.0      )
225
ECHO(flt, float,   -1.0,      1.0      )
226
ECHO(s16, int16_t, INT16_MIN, INT16_MAX)
227
ECHO(s32, int32_t, INT32_MIN, INT32_MAX)
228
 
229
static int config_output(AVFilterLink *outlink)
230
{
231
    AVFilterContext *ctx = outlink->src;
232
    AudioEchoContext *s = ctx->priv;
233
    float volume = 1.0;
234
    int i;
235
 
236
    for (i = 0; i < s->nb_echoes; i++) {
237
        s->samples[i] = s->delay[i] * outlink->sample_rate / 1000.0;
238
        s->max_samples = FFMAX(s->max_samples, s->samples[i]);
239
        volume += s->decay[i];
240
    }
241
 
242
    if (s->max_samples <= 0) {
243
        av_log(ctx, AV_LOG_ERROR, "Nothing to echo - missing delay samples.\n");
244
        return AVERROR(EINVAL);
245
    }
246
    s->fade_out = s->max_samples;
247
 
248
    if (volume * s->in_gain * s->out_gain > 1.0)
249
        av_log(ctx, AV_LOG_WARNING,
250
               "out_gain %f can cause saturation of output\n", s->out_gain);
251
 
252
    switch (outlink->format) {
253
    case AV_SAMPLE_FMT_DBLP: s->echo_samples = echo_samples_dblp; break;
254
    case AV_SAMPLE_FMT_FLTP: s->echo_samples = echo_samples_fltp; break;
255
    case AV_SAMPLE_FMT_S16P: s->echo_samples = echo_samples_s16p; break;
256
    case AV_SAMPLE_FMT_S32P: s->echo_samples = echo_samples_s32p; break;
257
    }
258
 
259
 
260
    if (s->delayptrs)
261
        av_freep(&s->delayptrs[0]);
262
    av_freep(&s->delayptrs);
263
 
264
    return av_samples_alloc_array_and_samples(&s->delayptrs, NULL,
265
                                              outlink->channels,
266
                                              s->max_samples,
267
                                              outlink->format, 0);
268
}
269
 
270
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
271
{
272
    AVFilterContext *ctx = inlink->dst;
273
    AudioEchoContext *s = ctx->priv;
274
    AVFrame *out_frame;
275
 
276
    if (av_frame_is_writable(frame)) {
277
        out_frame = frame;
278
    } else {
279
        out_frame = ff_get_audio_buffer(inlink, frame->nb_samples);
280
        if (!out_frame)
281
            return AVERROR(ENOMEM);
282
        av_frame_copy_props(out_frame, frame);
283
    }
284
 
285
    s->echo_samples(s, s->delayptrs, frame->extended_data, out_frame->extended_data,
286
                    frame->nb_samples, inlink->channels);
287
 
288
    if (frame != out_frame)
289
        av_frame_free(&frame);
290
 
291
    s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
292
    return ff_filter_frame(ctx->outputs[0], out_frame);
293
}
294
 
295
static int request_frame(AVFilterLink *outlink)
296
{
297
    AVFilterContext *ctx = outlink->src;
298
    AudioEchoContext *s = ctx->priv;
299
    int ret;
300
 
301
    ret = ff_request_frame(ctx->inputs[0]);
302
 
303
    if (ret == AVERROR_EOF && !ctx->is_disabled && s->fade_out) {
304
        int nb_samples = FFMIN(s->fade_out, 2048);
305
        AVFrame *frame;
306
 
307
        frame = ff_get_audio_buffer(outlink, nb_samples);
308
        if (!frame)
309
            return AVERROR(ENOMEM);
310
        s->fade_out -= nb_samples;
311
 
312
        av_samples_set_silence(frame->extended_data, 0,
313
                               frame->nb_samples,
314
                               outlink->channels,
315
                               frame->format);
316
 
317
        s->echo_samples(s, s->delayptrs, frame->extended_data, frame->extended_data,
318
                        frame->nb_samples, outlink->channels);
319
 
320
        frame->pts = s->next_pts;
321
        if (s->next_pts != AV_NOPTS_VALUE)
322
            s->next_pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
323
 
324
        return ff_filter_frame(outlink, frame);
325
    }
326
 
327
    return ret;
328
}
329
 
330
static const AVFilterPad aecho_inputs[] = {
331
    {
332
        .name         = "default",
333
        .type         = AVMEDIA_TYPE_AUDIO,
334
        .filter_frame = filter_frame,
335
    },
336
    { NULL }
337
};
338
 
339
static const AVFilterPad aecho_outputs[] = {
340
    {
341
        .name          = "default",
342
        .request_frame = request_frame,
343
        .config_props  = config_output,
344
        .type          = AVMEDIA_TYPE_AUDIO,
345
    },
346
    { NULL }
347
};
348
 
349
AVFilter avfilter_af_aecho = {
350
    .name          = "aecho",
351
    .description   = NULL_IF_CONFIG_SMALL("Add echoing to the audio."),
352
    .query_formats = query_formats,
353
    .priv_size     = sizeof(AudioEchoContext),
354
    .priv_class    = &aecho_class,
355
    .init          = init,
356
    .uninit        = uninit,
357
    .inputs        = aecho_inputs,
358
    .outputs       = aecho_outputs,
359
};