blob: 9acadc51c50353e1ece23d1b7f05f0728b0769a0
1 | /* |
2 | * Copyright (c) 2013-2015 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 | * fade audio filter |
24 | */ |
25 | |
26 | #include "libavutil/audio_fifo.h" |
27 | #include "libavutil/opt.h" |
28 | #include "audio.h" |
29 | #include "avfilter.h" |
30 | #include "internal.h" |
31 | |
32 | typedef struct { |
33 | const AVClass *class; |
34 | int type; |
35 | int curve, curve2; |
36 | int nb_samples; |
37 | int64_t start_sample; |
38 | int64_t duration; |
39 | int64_t start_time; |
40 | int overlap; |
41 | int cf0_eof; |
42 | int crossfade_is_over; |
43 | AVAudioFifo *fifo[2]; |
44 | int64_t pts; |
45 | |
46 | void (*fade_samples)(uint8_t **dst, uint8_t * const *src, |
47 | int nb_samples, int channels, int direction, |
48 | int64_t start, int range, int curve); |
49 | void (*crossfade_samples)(uint8_t **dst, uint8_t * const *cf0, |
50 | uint8_t * const *cf1, |
51 | int nb_samples, int channels, |
52 | int curve0, int curve1); |
53 | } AudioFadeContext; |
54 | |
55 | enum CurveType { TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR, PAR, EXP, IQSIN, IHSIN, DESE, DESI, NB_CURVES }; |
56 | |
57 | #define OFFSET(x) offsetof(AudioFadeContext, x) |
58 | #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM |
59 | |
60 | static int query_formats(AVFilterContext *ctx) |
61 | { |
62 | AVFilterFormats *formats; |
63 | AVFilterChannelLayouts *layouts; |
64 | static const enum AVSampleFormat sample_fmts[] = { |
65 | AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, |
66 | AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, |
67 | AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, |
68 | AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, |
69 | AV_SAMPLE_FMT_NONE |
70 | }; |
71 | int ret; |
72 | |
73 | layouts = ff_all_channel_counts(); |
74 | if (!layouts) |
75 | return AVERROR(ENOMEM); |
76 | ret = ff_set_common_channel_layouts(ctx, layouts); |
77 | if (ret < 0) |
78 | return ret; |
79 | |
80 | formats = ff_make_format_list(sample_fmts); |
81 | if (!formats) |
82 | return AVERROR(ENOMEM); |
83 | ret = ff_set_common_formats(ctx, formats); |
84 | if (ret < 0) |
85 | return ret; |
86 | |
87 | formats = ff_all_samplerates(); |
88 | if (!formats) |
89 | return AVERROR(ENOMEM); |
90 | return ff_set_common_samplerates(ctx, formats); |
91 | } |
92 | |
93 | static double fade_gain(int curve, int64_t index, int range) |
94 | { |
95 | #define CUBE(a) ((a)*(a)*(a)) |
96 | double gain; |
97 | |
98 | gain = av_clipd(1.0 * index / range, 0, 1.0); |
99 | |
100 | switch (curve) { |
101 | case QSIN: |
102 | gain = sin(gain * M_PI / 2.0); |
103 | break; |
104 | case IQSIN: |
105 | /* 0.6... = 2 / M_PI */ |
106 | gain = 0.6366197723675814 * asin(gain); |
107 | break; |
108 | case ESIN: |
109 | gain = 1.0 - cos(M_PI / 4.0 * (CUBE(2.0*gain - 1) + 1)); |
110 | break; |
111 | case HSIN: |
112 | gain = (1.0 - cos(gain * M_PI)) / 2.0; |
113 | break; |
114 | case IHSIN: |
115 | /* 0.3... = 1 / M_PI */ |
116 | gain = 0.3183098861837907 * acos(1 - 2 * gain); |
117 | break; |
118 | case EXP: |
119 | /* -11.5... = 5*ln(0.1) */ |
120 | gain = exp(-11.512925464970227 * (1 - gain)); |
121 | break; |
122 | case LOG: |
123 | gain = av_clipd(1 + 0.2 * log10(gain), 0, 1.0); |
124 | break; |
125 | case PAR: |
126 | gain = 1 - sqrt(1 - gain); |
127 | break; |
128 | case IPAR: |
129 | gain = (1 - (1 - gain) * (1 - gain)); |
130 | break; |
131 | case QUA: |
132 | gain *= gain; |
133 | break; |
134 | case CUB: |
135 | gain = CUBE(gain); |
136 | break; |
137 | case SQU: |
138 | gain = sqrt(gain); |
139 | break; |
140 | case CBR: |
141 | gain = cbrt(gain); |
142 | break; |
143 | case DESE: |
144 | gain = gain <= 0.5 ? cbrt(2 * gain) / 2: 1 - cbrt(2 * (1 - gain)) / 2; |
145 | break; |
146 | case DESI: |
147 | gain = gain <= 0.5 ? CUBE(2 * gain) / 2: 1 - CUBE(2 * (1 - gain)) / 2; |
148 | break; |
149 | } |
150 | |
151 | return gain; |
152 | } |
153 | |
154 | #define FADE_PLANAR(name, type) \ |
155 | static void fade_samples_## name ##p(uint8_t **dst, uint8_t * const *src, \ |
156 | int nb_samples, int channels, int dir, \ |
157 | int64_t start, int range, int curve) \ |
158 | { \ |
159 | int i, c; \ |
160 | \ |
161 | for (i = 0; i < nb_samples; i++) { \ |
162 | double gain = fade_gain(curve, start + i * dir, range); \ |
163 | for (c = 0; c < channels; c++) { \ |
164 | type *d = (type *)dst[c]; \ |
165 | const type *s = (type *)src[c]; \ |
166 | \ |
167 | d[i] = s[i] * gain; \ |
168 | } \ |
169 | } \ |
170 | } |
171 | |
172 | #define FADE(name, type) \ |
173 | static void fade_samples_## name (uint8_t **dst, uint8_t * const *src, \ |
174 | int nb_samples, int channels, int dir, \ |
175 | int64_t start, int range, int curve) \ |
176 | { \ |
177 | type *d = (type *)dst[0]; \ |
178 | const type *s = (type *)src[0]; \ |
179 | int i, c, k = 0; \ |
180 | \ |
181 | for (i = 0; i < nb_samples; i++) { \ |
182 | double gain = fade_gain(curve, start + i * dir, range); \ |
183 | for (c = 0; c < channels; c++, k++) \ |
184 | d[k] = s[k] * gain; \ |
185 | } \ |
186 | } |
187 | |
188 | FADE_PLANAR(dbl, double) |
189 | FADE_PLANAR(flt, float) |
190 | FADE_PLANAR(s16, int16_t) |
191 | FADE_PLANAR(s32, int32_t) |
192 | |
193 | FADE(dbl, double) |
194 | FADE(flt, float) |
195 | FADE(s16, int16_t) |
196 | FADE(s32, int32_t) |
197 | |
198 | static int config_output(AVFilterLink *outlink) |
199 | { |
200 | AVFilterContext *ctx = outlink->src; |
201 | AudioFadeContext *s = ctx->priv; |
202 | |
203 | switch (outlink->format) { |
204 | case AV_SAMPLE_FMT_DBL: s->fade_samples = fade_samples_dbl; break; |
205 | case AV_SAMPLE_FMT_DBLP: s->fade_samples = fade_samples_dblp; break; |
206 | case AV_SAMPLE_FMT_FLT: s->fade_samples = fade_samples_flt; break; |
207 | case AV_SAMPLE_FMT_FLTP: s->fade_samples = fade_samples_fltp; break; |
208 | case AV_SAMPLE_FMT_S16: s->fade_samples = fade_samples_s16; break; |
209 | case AV_SAMPLE_FMT_S16P: s->fade_samples = fade_samples_s16p; break; |
210 | case AV_SAMPLE_FMT_S32: s->fade_samples = fade_samples_s32; break; |
211 | case AV_SAMPLE_FMT_S32P: s->fade_samples = fade_samples_s32p; break; |
212 | } |
213 | |
214 | if (s->duration) |
215 | s->nb_samples = av_rescale(s->duration, outlink->sample_rate, AV_TIME_BASE); |
216 | if (s->start_time) |
217 | s->start_sample = av_rescale(s->start_time, outlink->sample_rate, AV_TIME_BASE); |
218 | |
219 | return 0; |
220 | } |
221 | |
222 | #if CONFIG_AFADE_FILTER |
223 | |
224 | static const AVOption afade_options[] = { |
225 | { "type", "set the fade direction", OFFSET(type), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FLAGS, "type" }, |
226 | { "t", "set the fade direction", OFFSET(type), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FLAGS, "type" }, |
227 | { "in", "fade-in", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "type" }, |
228 | { "out", "fade-out", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "type" }, |
229 | { "start_sample", "set number of first sample to start fading", OFFSET(start_sample), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, FLAGS }, |
230 | { "ss", "set number of first sample to start fading", OFFSET(start_sample), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, FLAGS }, |
231 | { "nb_samples", "set number of samples for fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX, FLAGS }, |
232 | { "ns", "set number of samples for fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX, FLAGS }, |
233 | { "start_time", "set time to start fading", OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, |
234 | { "st", "set time to start fading", OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, |
235 | { "duration", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, |
236 | { "d", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, |
237 | { "curve", "set fade curve type", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, |
238 | { "c", "set fade curve type", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, |
239 | { "tri", "linear slope", 0, AV_OPT_TYPE_CONST, {.i64 = TRI }, 0, 0, FLAGS, "curve" }, |
240 | { "qsin", "quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = QSIN }, 0, 0, FLAGS, "curve" }, |
241 | { "esin", "exponential sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = ESIN }, 0, 0, FLAGS, "curve" }, |
242 | { "hsin", "half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = HSIN }, 0, 0, FLAGS, "curve" }, |
243 | { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64 = LOG }, 0, 0, FLAGS, "curve" }, |
244 | { "ipar", "inverted parabola", 0, AV_OPT_TYPE_CONST, {.i64 = IPAR }, 0, 0, FLAGS, "curve" }, |
245 | { "qua", "quadratic", 0, AV_OPT_TYPE_CONST, {.i64 = QUA }, 0, 0, FLAGS, "curve" }, |
246 | { "cub", "cubic", 0, AV_OPT_TYPE_CONST, {.i64 = CUB }, 0, 0, FLAGS, "curve" }, |
247 | { "squ", "square root", 0, AV_OPT_TYPE_CONST, {.i64 = SQU }, 0, 0, FLAGS, "curve" }, |
248 | { "cbr", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64 = CBR }, 0, 0, FLAGS, "curve" }, |
249 | { "par", "parabola", 0, AV_OPT_TYPE_CONST, {.i64 = PAR }, 0, 0, FLAGS, "curve" }, |
250 | { "exp", "exponential", 0, AV_OPT_TYPE_CONST, {.i64 = EXP }, 0, 0, FLAGS, "curve" }, |
251 | { "iqsin", "inverted quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IQSIN}, 0, 0, FLAGS, "curve" }, |
252 | { "ihsin", "inverted half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IHSIN}, 0, 0, FLAGS, "curve" }, |
253 | { "dese", "double-exponential seat", 0, AV_OPT_TYPE_CONST, {.i64 = DESE }, 0, 0, FLAGS, "curve" }, |
254 | { "desi", "double-exponential sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = DESI }, 0, 0, FLAGS, "curve" }, |
255 | { NULL } |
256 | }; |
257 | |
258 | AVFILTER_DEFINE_CLASS(afade); |
259 | |
260 | static av_cold int init(AVFilterContext *ctx) |
261 | { |
262 | AudioFadeContext *s = ctx->priv; |
263 | |
264 | if (INT64_MAX - s->nb_samples < s->start_sample) |
265 | return AVERROR(EINVAL); |
266 | |
267 | return 0; |
268 | } |
269 | |
270 | static int filter_frame(AVFilterLink *inlink, AVFrame *buf) |
271 | { |
272 | AudioFadeContext *s = inlink->dst->priv; |
273 | AVFilterLink *outlink = inlink->dst->outputs[0]; |
274 | int nb_samples = buf->nb_samples; |
275 | AVFrame *out_buf; |
276 | int64_t cur_sample = av_rescale_q(buf->pts, inlink->time_base, (AVRational){1, inlink->sample_rate}); |
277 | |
278 | if ((!s->type && (s->start_sample + s->nb_samples < cur_sample)) || |
279 | ( s->type && (cur_sample + nb_samples < s->start_sample))) |
280 | return ff_filter_frame(outlink, buf); |
281 | |
282 | if (av_frame_is_writable(buf)) { |
283 | out_buf = buf; |
284 | } else { |
285 | out_buf = ff_get_audio_buffer(inlink, nb_samples); |
286 | if (!out_buf) |
287 | return AVERROR(ENOMEM); |
288 | av_frame_copy_props(out_buf, buf); |
289 | } |
290 | |
291 | if ((!s->type && (cur_sample + nb_samples < s->start_sample)) || |
292 | ( s->type && (s->start_sample + s->nb_samples < cur_sample))) { |
293 | av_samples_set_silence(out_buf->extended_data, 0, nb_samples, |
294 | av_frame_get_channels(out_buf), out_buf->format); |
295 | } else { |
296 | int64_t start; |
297 | |
298 | if (!s->type) |
299 | start = cur_sample - s->start_sample; |
300 | else |
301 | start = s->start_sample + s->nb_samples - cur_sample; |
302 | |
303 | s->fade_samples(out_buf->extended_data, buf->extended_data, |
304 | nb_samples, av_frame_get_channels(buf), |
305 | s->type ? -1 : 1, start, |
306 | s->nb_samples, s->curve); |
307 | } |
308 | |
309 | if (buf != out_buf) |
310 | av_frame_free(&buf); |
311 | |
312 | return ff_filter_frame(outlink, out_buf); |
313 | } |
314 | |
315 | static const AVFilterPad avfilter_af_afade_inputs[] = { |
316 | { |
317 | .name = "default", |
318 | .type = AVMEDIA_TYPE_AUDIO, |
319 | .filter_frame = filter_frame, |
320 | }, |
321 | { NULL } |
322 | }; |
323 | |
324 | static const AVFilterPad avfilter_af_afade_outputs[] = { |
325 | { |
326 | .name = "default", |
327 | .type = AVMEDIA_TYPE_AUDIO, |
328 | .config_props = config_output, |
329 | }, |
330 | { NULL } |
331 | }; |
332 | |
333 | AVFilter ff_af_afade = { |
334 | .name = "afade", |
335 | .description = NULL_IF_CONFIG_SMALL("Fade in/out input audio."), |
336 | .query_formats = query_formats, |
337 | .priv_size = sizeof(AudioFadeContext), |
338 | .init = init, |
339 | .inputs = avfilter_af_afade_inputs, |
340 | .outputs = avfilter_af_afade_outputs, |
341 | .priv_class = &afade_class, |
342 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, |
343 | }; |
344 | |
345 | #endif /* CONFIG_AFADE_FILTER */ |
346 | |
347 | #if CONFIG_ACROSSFADE_FILTER |
348 | |
349 | static const AVOption acrossfade_options[] = { |
350 | { "nb_samples", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX/10, FLAGS }, |
351 | { "ns", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX/10, FLAGS }, |
352 | { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, 60, FLAGS }, |
353 | { "d", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, 60, FLAGS }, |
354 | { "overlap", "overlap 1st stream end with 2nd stream start", OFFSET(overlap), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, FLAGS }, |
355 | { "o", "overlap 1st stream end with 2nd stream start", OFFSET(overlap), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, FLAGS }, |
356 | { "curve1", "set fade curve type for 1st stream", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, |
357 | { "c1", "set fade curve type for 1st stream", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, |
358 | { "tri", "linear slope", 0, AV_OPT_TYPE_CONST, {.i64 = TRI }, 0, 0, FLAGS, "curve" }, |
359 | { "qsin", "quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = QSIN }, 0, 0, FLAGS, "curve" }, |
360 | { "esin", "exponential sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = ESIN }, 0, 0, FLAGS, "curve" }, |
361 | { "hsin", "half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = HSIN }, 0, 0, FLAGS, "curve" }, |
362 | { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64 = LOG }, 0, 0, FLAGS, "curve" }, |
363 | { "ipar", "inverted parabola", 0, AV_OPT_TYPE_CONST, {.i64 = IPAR }, 0, 0, FLAGS, "curve" }, |
364 | { "qua", "quadratic", 0, AV_OPT_TYPE_CONST, {.i64 = QUA }, 0, 0, FLAGS, "curve" }, |
365 | { "cub", "cubic", 0, AV_OPT_TYPE_CONST, {.i64 = CUB }, 0, 0, FLAGS, "curve" }, |
366 | { "squ", "square root", 0, AV_OPT_TYPE_CONST, {.i64 = SQU }, 0, 0, FLAGS, "curve" }, |
367 | { "cbr", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64 = CBR }, 0, 0, FLAGS, "curve" }, |
368 | { "par", "parabola", 0, AV_OPT_TYPE_CONST, {.i64 = PAR }, 0, 0, FLAGS, "curve" }, |
369 | { "exp", "exponential", 0, AV_OPT_TYPE_CONST, {.i64 = EXP }, 0, 0, FLAGS, "curve" }, |
370 | { "iqsin", "inverted quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IQSIN}, 0, 0, FLAGS, "curve" }, |
371 | { "ihsin", "inverted half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IHSIN}, 0, 0, FLAGS, "curve" }, |
372 | { "dese", "double-exponential seat", 0, AV_OPT_TYPE_CONST, {.i64 = DESE }, 0, 0, FLAGS, "curve" }, |
373 | { "desi", "double-exponential sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = DESI }, 0, 0, FLAGS, "curve" }, |
374 | { "curve2", "set fade curve type for 2nd stream", OFFSET(curve2), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, |
375 | { "c2", "set fade curve type for 2nd stream", OFFSET(curve2), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, |
376 | { NULL } |
377 | }; |
378 | |
379 | AVFILTER_DEFINE_CLASS(acrossfade); |
380 | |
381 | #define CROSSFADE_PLANAR(name, type) \ |
382 | static void crossfade_samples_## name ##p(uint8_t **dst, uint8_t * const *cf0, \ |
383 | uint8_t * const *cf1, \ |
384 | int nb_samples, int channels, \ |
385 | int curve0, int curve1) \ |
386 | { \ |
387 | int i, c; \ |
388 | \ |
389 | for (i = 0; i < nb_samples; i++) { \ |
390 | double gain0 = fade_gain(curve0, nb_samples - 1 - i, nb_samples); \ |
391 | double gain1 = fade_gain(curve1, i, nb_samples); \ |
392 | for (c = 0; c < channels; c++) { \ |
393 | type *d = (type *)dst[c]; \ |
394 | const type *s0 = (type *)cf0[c]; \ |
395 | const type *s1 = (type *)cf1[c]; \ |
396 | \ |
397 | d[i] = s0[i] * gain0 + s1[i] * gain1; \ |
398 | } \ |
399 | } \ |
400 | } |
401 | |
402 | #define CROSSFADE(name, type) \ |
403 | static void crossfade_samples_## name (uint8_t **dst, uint8_t * const *cf0, \ |
404 | uint8_t * const *cf1, \ |
405 | int nb_samples, int channels, \ |
406 | int curve0, int curve1) \ |
407 | { \ |
408 | type *d = (type *)dst[0]; \ |
409 | const type *s0 = (type *)cf0[0]; \ |
410 | const type *s1 = (type *)cf1[0]; \ |
411 | int i, c, k = 0; \ |
412 | \ |
413 | for (i = 0; i < nb_samples; i++) { \ |
414 | double gain0 = fade_gain(curve0, nb_samples - 1 - i, nb_samples); \ |
415 | double gain1 = fade_gain(curve1, i, nb_samples); \ |
416 | for (c = 0; c < channels; c++, k++) \ |
417 | d[k] = s0[k] * gain0 + s1[k] * gain1; \ |
418 | } \ |
419 | } |
420 | |
421 | CROSSFADE_PLANAR(dbl, double) |
422 | CROSSFADE_PLANAR(flt, float) |
423 | CROSSFADE_PLANAR(s16, int16_t) |
424 | CROSSFADE_PLANAR(s32, int32_t) |
425 | |
426 | CROSSFADE(dbl, double) |
427 | CROSSFADE(flt, float) |
428 | CROSSFADE(s16, int16_t) |
429 | CROSSFADE(s32, int32_t) |
430 | |
431 | static int acrossfade_filter_frame(AVFilterLink *inlink, AVFrame *in) |
432 | { |
433 | AVFilterContext *ctx = inlink->dst; |
434 | AudioFadeContext *s = ctx->priv; |
435 | AVFilterLink *outlink = ctx->outputs[0]; |
436 | AVFrame *out, *cf[2] = { NULL }; |
437 | int ret = 0, nb_samples; |
438 | |
439 | if (s->crossfade_is_over) { |
440 | in->pts = s->pts; |
441 | s->pts += av_rescale_q(in->nb_samples, |
442 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); |
443 | return ff_filter_frame(outlink, in); |
444 | } else if (inlink == ctx->inputs[0]) { |
445 | av_audio_fifo_write(s->fifo[0], (void **)in->extended_data, in->nb_samples); |
446 | |
447 | nb_samples = av_audio_fifo_size(s->fifo[0]) - s->nb_samples; |
448 | if (nb_samples > 0) { |
449 | out = ff_get_audio_buffer(outlink, nb_samples); |
450 | if (!out) { |
451 | ret = AVERROR(ENOMEM); |
452 | goto fail; |
453 | } |
454 | av_audio_fifo_read(s->fifo[0], (void **)out->extended_data, nb_samples); |
455 | out->pts = s->pts; |
456 | s->pts += av_rescale_q(nb_samples, |
457 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); |
458 | ret = ff_filter_frame(outlink, out); |
459 | } |
460 | } else if (av_audio_fifo_size(s->fifo[1]) < s->nb_samples) { |
461 | if (!s->overlap && av_audio_fifo_size(s->fifo[0]) > 0) { |
462 | nb_samples = av_audio_fifo_size(s->fifo[0]); |
463 | |
464 | cf[0] = ff_get_audio_buffer(outlink, nb_samples); |
465 | out = ff_get_audio_buffer(outlink, nb_samples); |
466 | if (!out || !cf[0]) { |
467 | ret = AVERROR(ENOMEM); |
468 | goto fail; |
469 | } |
470 | av_audio_fifo_read(s->fifo[0], (void **)cf[0]->extended_data, nb_samples); |
471 | |
472 | s->fade_samples(out->extended_data, cf[0]->extended_data, nb_samples, |
473 | outlink->channels, -1, nb_samples - 1, nb_samples, s->curve); |
474 | out->pts = s->pts; |
475 | s->pts += av_rescale_q(nb_samples, |
476 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); |
477 | ret = ff_filter_frame(outlink, out); |
478 | if (ret < 0) |
479 | goto fail; |
480 | } |
481 | |
482 | av_audio_fifo_write(s->fifo[1], (void **)in->extended_data, in->nb_samples); |
483 | } else if (av_audio_fifo_size(s->fifo[1]) >= s->nb_samples) { |
484 | av_audio_fifo_write(s->fifo[1], (void **)in->extended_data, in->nb_samples); |
485 | |
486 | if (s->overlap) { |
487 | cf[0] = ff_get_audio_buffer(outlink, s->nb_samples); |
488 | cf[1] = ff_get_audio_buffer(outlink, s->nb_samples); |
489 | out = ff_get_audio_buffer(outlink, s->nb_samples); |
490 | if (!out || !cf[0] || !cf[1]) { |
491 | av_frame_free(&out); |
492 | ret = AVERROR(ENOMEM); |
493 | goto fail; |
494 | } |
495 | |
496 | av_audio_fifo_read(s->fifo[0], (void **)cf[0]->extended_data, s->nb_samples); |
497 | av_audio_fifo_read(s->fifo[1], (void **)cf[1]->extended_data, s->nb_samples); |
498 | |
499 | s->crossfade_samples(out->extended_data, cf[0]->extended_data, |
500 | cf[1]->extended_data, |
501 | s->nb_samples, av_frame_get_channels(in), |
502 | s->curve, s->curve2); |
503 | out->pts = s->pts; |
504 | s->pts += av_rescale_q(s->nb_samples, |
505 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); |
506 | ret = ff_filter_frame(outlink, out); |
507 | if (ret < 0) |
508 | goto fail; |
509 | } else { |
510 | out = ff_get_audio_buffer(outlink, s->nb_samples); |
511 | cf[1] = ff_get_audio_buffer(outlink, s->nb_samples); |
512 | if (!out || !cf[1]) { |
513 | ret = AVERROR(ENOMEM); |
514 | av_frame_free(&out); |
515 | goto fail; |
516 | } |
517 | |
518 | av_audio_fifo_read(s->fifo[1], (void **)cf[1]->extended_data, s->nb_samples); |
519 | |
520 | s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples, |
521 | outlink->channels, 1, 0, s->nb_samples, s->curve2); |
522 | out->pts = s->pts; |
523 | s->pts += av_rescale_q(s->nb_samples, |
524 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); |
525 | ret = ff_filter_frame(outlink, out); |
526 | if (ret < 0) |
527 | goto fail; |
528 | } |
529 | |
530 | nb_samples = av_audio_fifo_size(s->fifo[1]); |
531 | if (nb_samples > 0) { |
532 | out = ff_get_audio_buffer(outlink, nb_samples); |
533 | if (!out) { |
534 | ret = AVERROR(ENOMEM); |
535 | goto fail; |
536 | } |
537 | |
538 | av_audio_fifo_read(s->fifo[1], (void **)out->extended_data, nb_samples); |
539 | out->pts = s->pts; |
540 | s->pts += av_rescale_q(nb_samples, |
541 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); |
542 | ret = ff_filter_frame(outlink, out); |
543 | } |
544 | s->crossfade_is_over = 1; |
545 | } |
546 | |
547 | fail: |
548 | av_frame_free(&in); |
549 | av_frame_free(&cf[0]); |
550 | av_frame_free(&cf[1]); |
551 | return ret; |
552 | } |
553 | |
554 | static int acrossfade_request_frame(AVFilterLink *outlink) |
555 | { |
556 | AVFilterContext *ctx = outlink->src; |
557 | AudioFadeContext *s = ctx->priv; |
558 | int ret = 0; |
559 | |
560 | if (!s->cf0_eof) { |
561 | AVFilterLink *cf0 = ctx->inputs[0]; |
562 | ret = ff_request_frame(cf0); |
563 | if (ret < 0 && ret != AVERROR_EOF) |
564 | return ret; |
565 | if (ret == AVERROR_EOF) { |
566 | s->cf0_eof = 1; |
567 | ret = 0; |
568 | } |
569 | } else { |
570 | AVFilterLink *cf1 = ctx->inputs[1]; |
571 | int nb_samples = av_audio_fifo_size(s->fifo[1]); |
572 | |
573 | ret = ff_request_frame(cf1); |
574 | if (ret == AVERROR_EOF && nb_samples > 0) { |
575 | AVFrame *out = ff_get_audio_buffer(outlink, nb_samples); |
576 | if (!out) |
577 | return AVERROR(ENOMEM); |
578 | |
579 | av_audio_fifo_read(s->fifo[1], (void **)out->extended_data, nb_samples); |
580 | ret = ff_filter_frame(outlink, out); |
581 | } |
582 | } |
583 | |
584 | return ret; |
585 | } |
586 | |
587 | static int acrossfade_config_output(AVFilterLink *outlink) |
588 | { |
589 | AVFilterContext *ctx = outlink->src; |
590 | AudioFadeContext *s = ctx->priv; |
591 | |
592 | if (ctx->inputs[0]->sample_rate != ctx->inputs[1]->sample_rate) { |
593 | av_log(ctx, AV_LOG_ERROR, |
594 | "Inputs must have the same sample rate " |
595 | "%d for in0 vs %d for in1\n", |
596 | ctx->inputs[0]->sample_rate, ctx->inputs[1]->sample_rate); |
597 | return AVERROR(EINVAL); |
598 | } |
599 | |
600 | outlink->sample_rate = ctx->inputs[0]->sample_rate; |
601 | outlink->time_base = ctx->inputs[0]->time_base; |
602 | outlink->channel_layout = ctx->inputs[0]->channel_layout; |
603 | outlink->channels = ctx->inputs[0]->channels; |
604 | |
605 | switch (outlink->format) { |
606 | case AV_SAMPLE_FMT_DBL: s->crossfade_samples = crossfade_samples_dbl; break; |
607 | case AV_SAMPLE_FMT_DBLP: s->crossfade_samples = crossfade_samples_dblp; break; |
608 | case AV_SAMPLE_FMT_FLT: s->crossfade_samples = crossfade_samples_flt; break; |
609 | case AV_SAMPLE_FMT_FLTP: s->crossfade_samples = crossfade_samples_fltp; break; |
610 | case AV_SAMPLE_FMT_S16: s->crossfade_samples = crossfade_samples_s16; break; |
611 | case AV_SAMPLE_FMT_S16P: s->crossfade_samples = crossfade_samples_s16p; break; |
612 | case AV_SAMPLE_FMT_S32: s->crossfade_samples = crossfade_samples_s32; break; |
613 | case AV_SAMPLE_FMT_S32P: s->crossfade_samples = crossfade_samples_s32p; break; |
614 | } |
615 | |
616 | config_output(outlink); |
617 | |
618 | s->fifo[0] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->nb_samples); |
619 | s->fifo[1] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->nb_samples); |
620 | if (!s->fifo[0] || !s->fifo[1]) |
621 | return AVERROR(ENOMEM); |
622 | |
623 | return 0; |
624 | } |
625 | |
626 | static av_cold void uninit(AVFilterContext *ctx) |
627 | { |
628 | AudioFadeContext *s = ctx->priv; |
629 | |
630 | av_audio_fifo_free(s->fifo[0]); |
631 | av_audio_fifo_free(s->fifo[1]); |
632 | } |
633 | |
634 | static const AVFilterPad avfilter_af_acrossfade_inputs[] = { |
635 | { |
636 | .name = "crossfade0", |
637 | .type = AVMEDIA_TYPE_AUDIO, |
638 | .filter_frame = acrossfade_filter_frame, |
639 | }, |
640 | { |
641 | .name = "crossfade1", |
642 | .type = AVMEDIA_TYPE_AUDIO, |
643 | .filter_frame = acrossfade_filter_frame, |
644 | }, |
645 | { NULL } |
646 | }; |
647 | |
648 | static const AVFilterPad avfilter_af_acrossfade_outputs[] = { |
649 | { |
650 | .name = "default", |
651 | .type = AVMEDIA_TYPE_AUDIO, |
652 | .request_frame = acrossfade_request_frame, |
653 | .config_props = acrossfade_config_output, |
654 | }, |
655 | { NULL } |
656 | }; |
657 | |
658 | AVFilter ff_af_acrossfade = { |
659 | .name = "acrossfade", |
660 | .description = NULL_IF_CONFIG_SMALL("Cross fade two input audio streams."), |
661 | .query_formats = query_formats, |
662 | .priv_size = sizeof(AudioFadeContext), |
663 | .uninit = uninit, |
664 | .priv_class = &acrossfade_class, |
665 | .inputs = avfilter_af_acrossfade_inputs, |
666 | .outputs = avfilter_af_acrossfade_outputs, |
667 | }; |
668 | |
669 | #endif /* CONFIG_ACROSSFADE_FILTER */ |
670 |