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