FFmpeg
Loading...
Searching...
No Matches
af_aecho.c
Go to the documentation of this file.
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/mem.h"
24#include "libavutil/opt.h"
25#include "libavutil/samplefmt.h"
26#include "avfilter.h"
27#include "audio.h"
28#include "filters.h"
29
30typedef struct AudioEchoContext {
31 const AVClass *class;
33 char *delays, *decays;
34 float *delay, *decay;
37 uint8_t **delayptrs;
39 int *samples;
40 int eof;
42
43 void (*echo_samples)(struct AudioEchoContext *ctx, uint8_t **delayptrs,
44 uint8_t * const *src, uint8_t **dst,
45 int nb_samples, int channels);
47
48#define OFFSET(x) offsetof(AudioEchoContext, x)
49#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
50
51static const AVOption aecho_options[] = {
52 { "in_gain", "set signal input gain", OFFSET(in_gain), AV_OPT_TYPE_FLOAT, {.dbl=0.6}, 0, 1, A },
53 { "out_gain", "set signal output gain", OFFSET(out_gain), AV_OPT_TYPE_FLOAT, {.dbl=0.3}, 0, 1, A },
54 { "delays", "set list of signal delays", OFFSET(delays), AV_OPT_TYPE_STRING, {.str="1000"}, 0, 0, A },
55 { "decays", "set list of signal decays", OFFSET(decays), AV_OPT_TYPE_STRING, {.str="0.5"}, 0, 0, A },
56 { NULL }
57};
58
60
61static void count_items(char *item_str, int *nb_items)
62{
63 char *p;
64
65 *nb_items = 1;
66 for (p = item_str; *p; p++) {
67 if (*p == '|')
68 (*nb_items)++;
69 }
70
71}
72
73static void fill_items(char *item_str, int *nb_items, float *items)
74{
75 char *p, *saveptr = NULL;
76 int i, new_nb_items = 0;
77
78 p = item_str;
79 for (i = 0; i < *nb_items; i++) {
80 char *tstr = av_strtok(p, "|", &saveptr);
81 p = NULL;
82 if (tstr)
83 new_nb_items += av_sscanf(tstr, "%f", &items[new_nb_items]) == 1;
84 }
85
86 *nb_items = new_nb_items;
87}
88
90{
91 AudioEchoContext *s = ctx->priv;
92
93 av_freep(&s->delay);
94 av_freep(&s->decay);
95 av_freep(&s->samples);
96
97 if (s->delayptrs)
98 av_freep(&s->delayptrs[0]);
99 av_freep(&s->delayptrs);
100}
101
103{
104 AudioEchoContext *s = ctx->priv;
105 int nb_delays, nb_decays, i;
106
107 if (!s->delays || !s->decays) {
108 av_log(ctx, AV_LOG_ERROR, "Missing delays and/or decays.\n");
109 return AVERROR(EINVAL);
110 }
111
112 count_items(s->delays, &nb_delays);
113 count_items(s->decays, &nb_decays);
114
115 s->delay = av_realloc_f(s->delay, nb_delays, sizeof(*s->delay));
116 s->decay = av_realloc_f(s->decay, nb_decays, sizeof(*s->decay));
117 if (!s->delay || !s->decay)
118 return AVERROR(ENOMEM);
119
120 fill_items(s->delays, &nb_delays, s->delay);
121 fill_items(s->decays, &nb_decays, s->decay);
122
123 if (nb_delays != nb_decays) {
124 av_log(ctx, AV_LOG_ERROR, "Number of delays %d differs from number of decays %d.\n", nb_delays, nb_decays);
125 return AVERROR(EINVAL);
126 }
127
128 s->nb_echoes = nb_delays;
129 if (!s->nb_echoes) {
130 av_log(ctx, AV_LOG_ERROR, "At least one decay & delay must be set.\n");
131 return AVERROR(EINVAL);
132 }
133
134 s->samples = av_realloc_f(s->samples, nb_delays, sizeof(*s->samples));
135 if (!s->samples)
136 return AVERROR(ENOMEM);
137
138 for (i = 0; i < nb_delays; i++) {
139 if (s->delay[i] <= 0 || s->delay[i] > 90000) {
140 av_log(ctx, AV_LOG_ERROR, "delay[%d]: %f is out of allowed range: (0, 90000]\n", i, s->delay[i]);
141 return AVERROR(EINVAL);
142 }
143 if (s->decay[i] <= 0 || s->decay[i] > 1) {
144 av_log(ctx, AV_LOG_ERROR, "decay[%d]: %f is out of allowed range: (0, 1]\n", i, s->decay[i]);
145 return AVERROR(EINVAL);
146 }
147 }
148
149 s->next_pts = AV_NOPTS_VALUE;
150
151 av_log(ctx, AV_LOG_DEBUG, "nb_echoes:%d\n", s->nb_echoes);
152 return 0;
153}
154
155#define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a))
156
157#define ECHO(name, type, min, max) \
158static void echo_samples_## name ##p(AudioEchoContext *ctx, \
159 uint8_t **delayptrs, \
160 uint8_t * const *src, uint8_t **dst, \
161 int nb_samples, int channels) \
162{ \
163 const double out_gain = ctx->out_gain; \
164 const double in_gain = ctx->in_gain; \
165 const int nb_echoes = ctx->nb_echoes; \
166 const int max_samples = ctx->max_samples; \
167 int i, j, chan, av_uninit(index); \
168 \
169 av_assert1(channels > 0); /* would corrupt delay_index */ \
170 \
171 for (chan = 0; chan < channels; chan++) { \
172 const type *s = (type *)src[chan]; \
173 type *d = (type *)dst[chan]; \
174 type *dbuf = (type *)delayptrs[chan]; \
175 \
176 index = ctx->delay_index; \
177 for (i = 0; i < nb_samples; i++, s++, d++) { \
178 double out, in; \
179 \
180 in = *s; \
181 out = in * in_gain; \
182 for (j = 0; j < nb_echoes; j++) { \
183 int ix = index + max_samples - ctx->samples[j]; \
184 ix = MOD(ix, max_samples); \
185 out += dbuf[ix] * ctx->decay[j]; \
186 } \
187 out *= out_gain; \
188 \
189 *d = av_clipd(out, min, max); \
190 dbuf[index] = in; \
191 \
192 index = MOD(index + 1, max_samples); \
193 } \
194 } \
195 ctx->delay_index = index; \
196}
197
198ECHO(dbl, double, -1.0, 1.0 )
199ECHO(flt, float, -1.0, 1.0 )
200ECHO(s16, int16_t, INT16_MIN, INT16_MAX)
201ECHO(s32, int32_t, INT32_MIN, INT32_MAX)
202
203static int config_output(AVFilterLink *outlink)
204{
205 AVFilterContext *ctx = outlink->src;
206 AudioEchoContext *s = ctx->priv;
207 float volume = 1.0;
208 int i;
209
210 for (i = 0; i < s->nb_echoes; i++) {
211 s->samples[i] = s->delay[i] * outlink->sample_rate / 1000.0;
212 s->max_samples = FFMAX(s->max_samples, s->samples[i]);
213 volume += s->decay[i];
214 }
215
216 if (s->max_samples <= 0) {
217 av_log(ctx, AV_LOG_ERROR, "Nothing to echo - missing delay samples.\n");
218 return AVERROR(EINVAL);
219 }
220 s->fade_out = s->max_samples;
221
222 if (volume * s->in_gain * s->out_gain > 1.0)
224 "out_gain %f can cause saturation of output\n", s->out_gain);
225
226 switch (outlink->format) {
227 case AV_SAMPLE_FMT_DBLP: s->echo_samples = echo_samples_dblp; break;
228 case AV_SAMPLE_FMT_FLTP: s->echo_samples = echo_samples_fltp; break;
229 case AV_SAMPLE_FMT_S16P: s->echo_samples = echo_samples_s16p; break;
230 case AV_SAMPLE_FMT_S32P: s->echo_samples = echo_samples_s32p; break;
231 }
232
233
234 if (s->delayptrs)
235 av_freep(&s->delayptrs[0]);
236 av_freep(&s->delayptrs);
237
238 return av_samples_alloc_array_and_samples(&s->delayptrs, NULL,
239 outlink->ch_layout.nb_channels,
240 s->max_samples,
241 outlink->format, 0);
242}
243
245{
246 AVFilterContext *ctx = inlink->dst;
247 AudioEchoContext *s = ctx->priv;
248 AVFrame *out_frame;
249
251 out_frame = frame;
252 } else {
253 out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples);
254 if (!out_frame) {
256 return AVERROR(ENOMEM);
257 }
258 av_frame_copy_props(out_frame, frame);
259 }
260
261 s->echo_samples(s, s->delayptrs, frame->extended_data, out_frame->extended_data,
262 frame->nb_samples, inlink->ch_layout.nb_channels);
263
264 s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
265
266 if (frame != out_frame)
268
269 return ff_filter_frame(ctx->outputs[0], out_frame);
270}
271
272static int request_frame(AVFilterLink *outlink)
273{
274 AVFilterContext *ctx = outlink->src;
275 AudioEchoContext *s = ctx->priv;
276 int nb_samples = FFMIN(s->fade_out, 2048);
277 AVFrame *frame = ff_get_audio_buffer(outlink, nb_samples);
278
279 if (!frame)
280 return AVERROR(ENOMEM);
281 s->fade_out -= nb_samples;
282
283 av_samples_set_silence(frame->extended_data, 0,
284 frame->nb_samples,
285 outlink->ch_layout.nb_channels,
286 frame->format);
287
288 s->echo_samples(s, s->delayptrs, frame->extended_data, frame->extended_data,
289 frame->nb_samples, outlink->ch_layout.nb_channels);
290
291 frame->pts = s->next_pts;
292 if (s->next_pts != AV_NOPTS_VALUE)
293 s->next_pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
294
295 return ff_filter_frame(outlink, frame);
296}
297
299{
300 AVFilterLink *inlink = ctx->inputs[0];
301 AVFilterLink *outlink = ctx->outputs[0];
302 AudioEchoContext *s = ctx->priv;
303 AVFrame *in;
304 int ret, status;
305 int64_t pts;
306
307 FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
308
309 ret = ff_inlink_consume_frame(inlink, &in);
310 if (ret < 0)
311 return ret;
312 if (ret > 0)
313 return filter_frame(inlink, in);
314
315 if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
316 if (status == AVERROR_EOF)
317 s->eof = 1;
318 }
319
320 if (s->eof && s->fade_out <= 0) {
321 ff_outlink_set_status(outlink, AVERROR_EOF, s->next_pts);
322 return 0;
323 }
324
325 if (!s->eof)
326 FF_FILTER_FORWARD_WANTED(outlink, inlink);
327
328 return request_frame(outlink);
329}
330
331static const AVFilterPad aecho_outputs[] = {
332 {
333 .name = "default",
334 .config_props = config_output,
335 .type = AVMEDIA_TYPE_AUDIO,
336 },
337};
338
340 .p.name = "aecho",
341 .p.description = NULL_IF_CONFIG_SMALL("Add echoing to the audio."),
342 .p.priv_class = &aecho_class,
343 .priv_size = sizeof(AudioEchoContext),
344 .init = init,
346 .uninit = uninit,
351};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static const AVOption aecho_options[]
Definition af_aecho.c:51
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition af_aecho.c:244
static int request_frame(AVFilterLink *outlink)
Definition af_aecho.c:272
static const AVFilterPad aecho_outputs[]
Definition af_aecho.c:331
#define ECHO(name, type, min, max)
Definition af_aecho.c:157
static int activate(AVFilterContext *ctx)
Definition af_aecho.c:298
static av_cold void uninit(AVFilterContext *ctx)
Definition af_aecho.c:89
#define OFFSET(x)
Definition af_aecho.c:48
const FFFilter ff_af_aecho
Definition af_aecho.c:339
static void count_items(char *item_str, int *nb_items)
Definition af_aecho.c:61
static void fill_items(char *item_str, int *nb_items, float *items)
Definition af_aecho.c:73
channels
Definition aptx.h:31
#define A(x)
Definition vpx_arith.h:28
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
Definition audio.c:34
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition audio.c:74
int32_t
simple assert() macros that are a bit more flexible than ISO C assert().
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
Definition avfilter.c:1467
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
Definition avfilter.c:1520
Main libavfilter public API header.
int av_sscanf(const char *string, const char *format,...)
Definition avsscanf.c:962
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVFrame * frame
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
Definition opt.h:270
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition frame.c:535
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
@ AV_SAMPLE_FMT_FLTP
float, planar
Definition samplefmt.h:66
@ AV_SAMPLE_FMT_S16P
signed 16 bits, planar
Definition samplefmt.h:64
@ AV_SAMPLE_FMT_S32P
signed 32 bits, planar
Definition samplefmt.h:65
@ AV_SAMPLE_FMT_DBLP
double, planar
Definition samplefmt.h:67
int av_samples_set_silence(uint8_t *const *audio_data, int offset, int nb_samples, int nb_channels, enum AVSampleFormat sample_fmt)
Fill an audio buffer with silence.
Definition samplefmt.c:246
int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align)
Allocate a data pointers array, samples buffer for nb_samples samples, and fill data pointers and lin...
Definition samplefmt.c:207
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition avstring.c:179
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
if(svq3)
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
static int config_output(AVBitStreamFilterLink *outlink)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FILTER_SAMPLEFMTS(...)
Definition filters.h:252
#define FF_FILTER_FORWARD_WANTED(outlink, inlink)
Forward the frame_wanted_out flag from an output link to an input link.
Definition filters.h:694
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
Definition filters.h:629
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
Definition filters.h:639
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
Memory handling functions.
AVOptions.
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
uint8_t ** extended_data
pointers to the data planes/channels.
Definition frame.h:533
AVOption.
Definition opt.h:428
Rational number (pair of numerator and denominator).
Definition rational.h:58
float * delay
Definition af_aecho.c:34
float * decay
Definition af_aecho.c:34
int64_t next_pts
Definition af_aecho.c:41
uint8_t ** delayptrs
Definition af_aecho.c:37
void(* echo_samples)(struct AudioEchoContext *ctx, uint8_t **delayptrs, uint8_t *const *src, uint8_t **dst, int nb_samples, int channels)
Definition af_aecho.c:43
#define av_realloc_f(p, o, n)
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
static AVFormatContext * ctx
Definition movenc.c:49
static int64_t pts