Browse code

avfilter: add acrossfade filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2015/07/24 07:13:17
Showing 6 changed files
... ...
@@ -26,6 +26,7 @@ version <next>:
26 26
 - AAC fixed-point decoding
27 27
 - sidechaincompress audio filter
28 28
 - bitstream filter for converting HEVC from MP4 to Annex B
29
+- acrossfade audio filter
29 30
 
30 31
 
31 32
 version 2.7:
... ...
@@ -318,6 +318,54 @@ build.
318 318
 
319 319
 Below is a description of the currently available audio filters.
320 320
 
321
+@section acrossfade
322
+
323
+Apply cross fade from one input audio stream to another input audio stream.
324
+The cross fade is applied for specified duration near the end of first stream.
325
+
326
+The filter accepts the following options:
327
+
328
+@table @option
329
+@item nb_samples, ns
330
+Specify the number of samples for which the cross fade effect has to last.
331
+At the end of the cross fade effect the first input audio will be completely
332
+silent. Default is 44100.
333
+
334
+@item duration, d
335
+Specify the duration of the cross fade effect. See
336
+@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}
337
+for the accepted syntax.
338
+By default the duration is determined by @var{nb_samples}.
339
+If set this option is used instead of @var{nb_samples}.
340
+
341
+@item overlap, o
342
+Should first stream end overlap with second stream start. Default is enabled.
343
+
344
+@item curve1
345
+Set curve for cross fade transition for first stream.
346
+
347
+@item curve2
348
+Set curve for cross fade transition for second stream.
349
+
350
+For description of available curve types see @ref{afade} filter description.
351
+@end table
352
+
353
+@subsection Examples
354
+
355
+@itemize
356
+@item
357
+Cross fade from one input to another:
358
+@example
359
+ffmpeg -i first.flac -i second.flac -filter_complex acrossfade=d=10:c1=exp:c2=exp output.flac
360
+@end example
361
+
362
+@item
363
+Cross fade from one input to another but without overlapping:
364
+@example
365
+ffmpeg -i first.flac -i second.flac -filter_complex acrossfade=d=10:o=0:c1=exp:c2=exp output.flac
366
+@end example
367
+@end itemize
368
+
321 369
 @section adelay
322 370
 
323 371
 Delay one or more audio channels.
... ...
@@ -469,6 +517,7 @@ aeval=val(0)|-val(1)
469 469
 @end example
470 470
 @end itemize
471 471
 
472
+@anchor{afade}
472 473
 @section afade
473 474
 
474 475
 Apply fade-in/out effect to input audio.
... ...
@@ -29,6 +29,7 @@ OBJS = allfilters.o                                                     \
29 29
 
30 30
 OBJS-$(CONFIG_AVCODEC)                       += avcodec.o
31 31
 
32
+OBJS-$(CONFIG_ACROSSFADE_FILTER)             += af_afade.o
32 33
 OBJS-$(CONFIG_ADELAY_FILTER)                 += af_adelay.o
33 34
 OBJS-$(CONFIG_AECHO_FILTER)                  += af_aecho.o
34 35
 OBJS-$(CONFIG_AEVAL_FILTER)                  += aeval.o
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- * Copyright (c) 2013 Paul B Mahol
2
+ * Copyright (c) 2013-2015 Paul B Mahol
3 3
  *
4 4
  * This file is part of FFmpeg.
5 5
  *
... ...
@@ -23,6 +23,7 @@
23 23
  * fade audio filter
24 24
  */
25 25
 
26
+#include "libavutil/audio_fifo.h"
26 27
 #include "libavutil/opt.h"
27 28
 #include "audio.h"
28 29
 #include "avfilter.h"
... ...
@@ -31,15 +32,24 @@
31 31
 typedef struct {
32 32
     const AVClass *class;
33 33
     int type;
34
-    int curve;
34
+    int curve, curve2;
35 35
     int nb_samples;
36 36
     int64_t start_sample;
37 37
     int64_t duration;
38 38
     int64_t start_time;
39
+    int overlap;
40
+    int cf0_eof;
41
+    int crossfade_is_over;
42
+    AVAudioFifo *fifo[2];
43
+    int64_t pts;
39 44
 
40 45
     void (*fade_samples)(uint8_t **dst, uint8_t * const *src,
41 46
                          int nb_samples, int channels, int direction,
42 47
                          int64_t start, int range, int curve);
48
+    void (*crossfade_samples)(uint8_t **dst, uint8_t * const *cf0,
49
+                              uint8_t * const *cf1,
50
+                              int nb_samples, int channels,
51
+                              int curve0, int curve1);
43 52
 } AudioFadeContext;
44 53
 
45 54
 enum CurveType { TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR, PAR, EXP, IQSIN, IHSIN, DESE, DESI, NB_CURVES };
... ...
@@ -47,52 +57,6 @@ enum CurveType { TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR, PAR, EXP,
47 47
 #define OFFSET(x) offsetof(AudioFadeContext, x)
48 48
 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
49 49
 
50
-static const AVOption afade_options[] = {
51
-    { "type",         "set the fade direction",                      OFFSET(type),         AV_OPT_TYPE_INT,    {.i64 = 0    }, 0, 1, FLAGS, "type" },
52
-    { "t",            "set the fade direction",                      OFFSET(type),         AV_OPT_TYPE_INT,    {.i64 = 0    }, 0, 1, FLAGS, "type" },
53
-    { "in",           "fade-in",                                     0,                    AV_OPT_TYPE_CONST,  {.i64 = 0    }, 0, 0, FLAGS, "type" },
54
-    { "out",          "fade-out",                                    0,                    AV_OPT_TYPE_CONST,  {.i64 = 1    }, 0, 0, FLAGS, "type" },
55
-    { "start_sample", "set number of first sample to start fading",  OFFSET(start_sample), AV_OPT_TYPE_INT64,  {.i64 = 0    }, 0, INT64_MAX, FLAGS },
56
-    { "ss",           "set number of first sample to start fading",  OFFSET(start_sample), AV_OPT_TYPE_INT64,  {.i64 = 0    }, 0, INT64_MAX, FLAGS },
57
-    { "nb_samples",   "set number of samples for fade duration",     OFFSET(nb_samples),   AV_OPT_TYPE_INT,    {.i64 = 44100}, 1, INT32_MAX, FLAGS },
58
-    { "ns",           "set number of samples for fade duration",     OFFSET(nb_samples),   AV_OPT_TYPE_INT,    {.i64 = 44100}, 1, INT32_MAX, FLAGS },
59
-    { "start_time",   "set time to start fading",                    OFFSET(start_time),   AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
60
-    { "st",           "set time to start fading",                    OFFSET(start_time),   AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
61
-    { "duration",     "set fade duration",                           OFFSET(duration),     AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
62
-    { "d",            "set fade duration",                           OFFSET(duration),     AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
63
-    { "curve",        "set fade curve type",                         OFFSET(curve),        AV_OPT_TYPE_INT,    {.i64 = TRI  }, 0, NB_CURVES - 1, FLAGS, "curve" },
64
-    { "c",            "set fade curve type",                         OFFSET(curve),        AV_OPT_TYPE_INT,    {.i64 = TRI  }, 0, NB_CURVES - 1, FLAGS, "curve" },
65
-    { "tri",          "linear slope",                                0,                    AV_OPT_TYPE_CONST,  {.i64 = TRI  }, 0, 0, FLAGS, "curve" },
66
-    { "qsin",         "quarter of sine wave",                        0,                    AV_OPT_TYPE_CONST,  {.i64 = QSIN }, 0, 0, FLAGS, "curve" },
67
-    { "esin",         "exponential sine wave",                       0,                    AV_OPT_TYPE_CONST,  {.i64 = ESIN }, 0, 0, FLAGS, "curve" },
68
-    { "hsin",         "half of sine wave",                           0,                    AV_OPT_TYPE_CONST,  {.i64 = HSIN }, 0, 0, FLAGS, "curve" },
69
-    { "log",          "logarithmic",                                 0,                    AV_OPT_TYPE_CONST,  {.i64 = LOG  }, 0, 0, FLAGS, "curve" },
70
-    { "ipar",         "inverted parabola",                           0,                    AV_OPT_TYPE_CONST,  {.i64 = IPAR }, 0, 0, FLAGS, "curve" },
71
-    { "qua",          "quadratic",                                   0,                    AV_OPT_TYPE_CONST,  {.i64 = QUA  }, 0, 0, FLAGS, "curve" },
72
-    { "cub",          "cubic",                                       0,                    AV_OPT_TYPE_CONST,  {.i64 = CUB  }, 0, 0, FLAGS, "curve" },
73
-    { "squ",          "square root",                                 0,                    AV_OPT_TYPE_CONST,  {.i64 = SQU  }, 0, 0, FLAGS, "curve" },
74
-    { "cbr",          "cubic root",                                  0,                    AV_OPT_TYPE_CONST,  {.i64 = CBR  }, 0, 0, FLAGS, "curve" },
75
-    { "par",          "parabola",                                    0,                    AV_OPT_TYPE_CONST,  {.i64 = PAR  }, 0, 0, FLAGS, "curve" },
76
-    { "exp",          "exponential",                                 0,                    AV_OPT_TYPE_CONST,  {.i64 = EXP  }, 0, 0, FLAGS, "curve" },
77
-    { "iqsin",        "inverted quarter of sine wave",               0,                    AV_OPT_TYPE_CONST,  {.i64 = IQSIN}, 0, 0, FLAGS, "curve" },
78
-    { "ihsin",        "inverted half of sine wave",                  0,                    AV_OPT_TYPE_CONST,  {.i64 = IHSIN}, 0, 0, FLAGS, "curve" },
79
-    { "dese",         "double-exponential seat",                     0,                    AV_OPT_TYPE_CONST,  {.i64 = DESE }, 0, 0, FLAGS, "curve" },
80
-    { "desi",         "double-exponential sigmoid",                  0,                    AV_OPT_TYPE_CONST,  {.i64 = DESI }, 0, 0, FLAGS, "curve" },
81
-    { NULL }
82
-};
83
-
84
-AVFILTER_DEFINE_CLASS(afade);
85
-
86
-static av_cold int init(AVFilterContext *ctx)
87
-{
88
-    AudioFadeContext *s = ctx->priv;
89
-
90
-    if (INT64_MAX - s->nb_samples < s->start_sample)
91
-        return AVERROR(EINVAL);
92
-
93
-    return 0;
94
-}
95
-
96 50
 static int query_formats(AVFilterContext *ctx)
97 51
 {
98 52
     AVFilterFormats *formats;
... ...
@@ -227,12 +191,12 @@ FADE(flt, float)
227 227
 FADE(s16, int16_t)
228 228
 FADE(s32, int32_t)
229 229
 
230
-static int config_input(AVFilterLink *inlink)
230
+static int config_output(AVFilterLink *outlink)
231 231
 {
232
-    AVFilterContext *ctx = inlink->dst;
232
+    AVFilterContext *ctx = outlink->src;
233 233
     AudioFadeContext *s  = ctx->priv;
234 234
 
235
-    switch (inlink->format) {
235
+    switch (outlink->format) {
236 236
     case AV_SAMPLE_FMT_DBL:  s->fade_samples = fade_samples_dbl;  break;
237 237
     case AV_SAMPLE_FMT_DBLP: s->fade_samples = fade_samples_dblp; break;
238 238
     case AV_SAMPLE_FMT_FLT:  s->fade_samples = fade_samples_flt;  break;
... ...
@@ -244,9 +208,57 @@ static int config_input(AVFilterLink *inlink)
244 244
     }
245 245
 
246 246
     if (s->duration)
247
-        s->nb_samples = av_rescale(s->duration, inlink->sample_rate, AV_TIME_BASE);
247
+        s->nb_samples = av_rescale(s->duration, outlink->sample_rate, AV_TIME_BASE);
248 248
     if (s->start_time)
249
-        s->start_sample = av_rescale(s->start_time, inlink->sample_rate, AV_TIME_BASE);
249
+        s->start_sample = av_rescale(s->start_time, outlink->sample_rate, AV_TIME_BASE);
250
+
251
+    return 0;
252
+}
253
+
254
+#if CONFIG_AFADE_FILTER
255
+
256
+static const AVOption afade_options[] = {
257
+    { "type",         "set the fade direction",                      OFFSET(type),         AV_OPT_TYPE_INT,    {.i64 = 0    }, 0, 1, FLAGS, "type" },
258
+    { "t",            "set the fade direction",                      OFFSET(type),         AV_OPT_TYPE_INT,    {.i64 = 0    }, 0, 1, FLAGS, "type" },
259
+    { "in",           "fade-in",                                     0,                    AV_OPT_TYPE_CONST,  {.i64 = 0    }, 0, 0, FLAGS, "type" },
260
+    { "out",          "fade-out",                                    0,                    AV_OPT_TYPE_CONST,  {.i64 = 1    }, 0, 0, FLAGS, "type" },
261
+    { "start_sample", "set number of first sample to start fading",  OFFSET(start_sample), AV_OPT_TYPE_INT64,  {.i64 = 0    }, 0, INT64_MAX, FLAGS },
262
+    { "ss",           "set number of first sample to start fading",  OFFSET(start_sample), AV_OPT_TYPE_INT64,  {.i64 = 0    }, 0, INT64_MAX, FLAGS },
263
+    { "nb_samples",   "set number of samples for fade duration",     OFFSET(nb_samples),   AV_OPT_TYPE_INT,    {.i64 = 44100}, 1, INT32_MAX, FLAGS },
264
+    { "ns",           "set number of samples for fade duration",     OFFSET(nb_samples),   AV_OPT_TYPE_INT,    {.i64 = 44100}, 1, INT32_MAX, FLAGS },
265
+    { "start_time",   "set time to start fading",                    OFFSET(start_time),   AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
266
+    { "st",           "set time to start fading",                    OFFSET(start_time),   AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
267
+    { "duration",     "set fade duration",                           OFFSET(duration),     AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
268
+    { "d",            "set fade duration",                           OFFSET(duration),     AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
269
+    { "curve",        "set fade curve type",                         OFFSET(curve),        AV_OPT_TYPE_INT,    {.i64 = TRI  }, 0, NB_CURVES - 1, FLAGS, "curve" },
270
+    { "c",            "set fade curve type",                         OFFSET(curve),        AV_OPT_TYPE_INT,    {.i64 = TRI  }, 0, NB_CURVES - 1, FLAGS, "curve" },
271
+    { "tri",          "linear slope",                                0,                    AV_OPT_TYPE_CONST,  {.i64 = TRI  }, 0, 0, FLAGS, "curve" },
272
+    { "qsin",         "quarter of sine wave",                        0,                    AV_OPT_TYPE_CONST,  {.i64 = QSIN }, 0, 0, FLAGS, "curve" },
273
+    { "esin",         "exponential sine wave",                       0,                    AV_OPT_TYPE_CONST,  {.i64 = ESIN }, 0, 0, FLAGS, "curve" },
274
+    { "hsin",         "half of sine wave",                           0,                    AV_OPT_TYPE_CONST,  {.i64 = HSIN }, 0, 0, FLAGS, "curve" },
275
+    { "log",          "logarithmic",                                 0,                    AV_OPT_TYPE_CONST,  {.i64 = LOG  }, 0, 0, FLAGS, "curve" },
276
+    { "ipar",         "inverted parabola",                           0,                    AV_OPT_TYPE_CONST,  {.i64 = IPAR }, 0, 0, FLAGS, "curve" },
277
+    { "qua",          "quadratic",                                   0,                    AV_OPT_TYPE_CONST,  {.i64 = QUA  }, 0, 0, FLAGS, "curve" },
278
+    { "cub",          "cubic",                                       0,                    AV_OPT_TYPE_CONST,  {.i64 = CUB  }, 0, 0, FLAGS, "curve" },
279
+    { "squ",          "square root",                                 0,                    AV_OPT_TYPE_CONST,  {.i64 = SQU  }, 0, 0, FLAGS, "curve" },
280
+    { "cbr",          "cubic root",                                  0,                    AV_OPT_TYPE_CONST,  {.i64 = CBR  }, 0, 0, FLAGS, "curve" },
281
+    { "par",          "parabola",                                    0,                    AV_OPT_TYPE_CONST,  {.i64 = PAR  }, 0, 0, FLAGS, "curve" },
282
+    { "exp",          "exponential",                                 0,                    AV_OPT_TYPE_CONST,  {.i64 = EXP  }, 0, 0, FLAGS, "curve" },
283
+    { "iqsin",        "inverted quarter of sine wave",               0,                    AV_OPT_TYPE_CONST,  {.i64 = IQSIN}, 0, 0, FLAGS, "curve" },
284
+    { "ihsin",        "inverted half of sine wave",                  0,                    AV_OPT_TYPE_CONST,  {.i64 = IHSIN}, 0, 0, FLAGS, "curve" },
285
+    { "dese",         "double-exponential seat",                     0,                    AV_OPT_TYPE_CONST,  {.i64 = DESE }, 0, 0, FLAGS, "curve" },
286
+    { "desi",         "double-exponential sigmoid",                  0,                    AV_OPT_TYPE_CONST,  {.i64 = DESI }, 0, 0, FLAGS, "curve" },
287
+    { NULL }
288
+};
289
+
290
+AVFILTER_DEFINE_CLASS(afade);
291
+
292
+static av_cold int init(AVFilterContext *ctx)
293
+{
294
+    AudioFadeContext *s = ctx->priv;
295
+
296
+    if (INT64_MAX - s->nb_samples < s->start_sample)
297
+        return AVERROR(EINVAL);
250 298
 
251 299
     return 0;
252 300
 }
... ...
@@ -301,15 +313,15 @@ static const AVFilterPad avfilter_af_afade_inputs[] = {
301 301
         .name         = "default",
302 302
         .type         = AVMEDIA_TYPE_AUDIO,
303 303
         .filter_frame = filter_frame,
304
-        .config_props = config_input,
305 304
     },
306 305
     { NULL }
307 306
 };
308 307
 
309 308
 static const AVFilterPad avfilter_af_afade_outputs[] = {
310 309
     {
311
-        .name = "default",
312
-        .type = AVMEDIA_TYPE_AUDIO,
310
+        .name         = "default",
311
+        .type         = AVMEDIA_TYPE_AUDIO,
312
+        .config_props = config_output,
313 313
     },
314 314
     { NULL }
315 315
 };
... ...
@@ -325,3 +337,344 @@ AVFilter ff_af_afade = {
325 325
     .priv_class    = &afade_class,
326 326
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
327 327
 };
328
+
329
+#endif /* CONFIG_AFADE_FILTER */
330
+
331
+#if CONFIG_ACROSSFADE_FILTER
332
+
333
+static const AVOption acrossfade_options[] = {
334
+    { "nb_samples",   "set number of samples for cross fade duration", OFFSET(nb_samples),   AV_OPT_TYPE_INT,    {.i64 = 44100}, 1, INT32_MAX/10, FLAGS },
335
+    { "ns",           "set number of samples for cross fade duration", OFFSET(nb_samples),   AV_OPT_TYPE_INT,    {.i64 = 44100}, 1, INT32_MAX/10, FLAGS },
336
+    { "duration",     "set cross fade duration",                       OFFSET(duration),     AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, 60, FLAGS },
337
+    { "d",            "set cross fade duration",                       OFFSET(duration),     AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, 60, FLAGS },
338
+    { "overlap",      "overlap 1st stream end with 2nd stream start",  OFFSET(overlap),      AV_OPT_TYPE_INT,    {.i64 = 1    }, 0,  1, FLAGS },
339
+    { "o",            "overlap 1st stream end with 2nd stream start",  OFFSET(overlap),      AV_OPT_TYPE_INT,    {.i64 = 1    }, 0,  1, FLAGS },
340
+    { "curve1",       "set fade curve type for 1st stream",            OFFSET(curve),        AV_OPT_TYPE_INT,    {.i64 = TRI  }, 0, NB_CURVES - 1, FLAGS, "curve1" },
341
+    { "c1",           "set fade curve type for 1st stream",            OFFSET(curve),        AV_OPT_TYPE_INT,    {.i64 = TRI  }, 0, NB_CURVES - 1, FLAGS, "curve1" },
342
+    {     "tri",      "linear slope",                                  0,                    AV_OPT_TYPE_CONST,  {.i64 = TRI  }, 0, 0, FLAGS, "curve1" },
343
+    {     "qsin",     "quarter of sine wave",                          0,                    AV_OPT_TYPE_CONST,  {.i64 = QSIN }, 0, 0, FLAGS, "curve1" },
344
+    {     "esin",     "exponential sine wave",                         0,                    AV_OPT_TYPE_CONST,  {.i64 = ESIN }, 0, 0, FLAGS, "curve1" },
345
+    {     "hsin",     "half of sine wave",                             0,                    AV_OPT_TYPE_CONST,  {.i64 = HSIN }, 0, 0, FLAGS, "curve1" },
346
+    {     "log",      "logarithmic",                                   0,                    AV_OPT_TYPE_CONST,  {.i64 = LOG  }, 0, 0, FLAGS, "curve1" },
347
+    {     "ipar",     "inverted parabola",                             0,                    AV_OPT_TYPE_CONST,  {.i64 = IPAR }, 0, 0, FLAGS, "curve1" },
348
+    {     "qua",      "quadratic",                                     0,                    AV_OPT_TYPE_CONST,  {.i64 = QUA  }, 0, 0, FLAGS, "curve1" },
349
+    {     "cub",      "cubic",                                         0,                    AV_OPT_TYPE_CONST,  {.i64 = CUB  }, 0, 0, FLAGS, "curve1" },
350
+    {     "squ",      "square root",                                   0,                    AV_OPT_TYPE_CONST,  {.i64 = SQU  }, 0, 0, FLAGS, "curve1" },
351
+    {     "cbr",      "cubic root",                                    0,                    AV_OPT_TYPE_CONST,  {.i64 = CBR  }, 0, 0, FLAGS, "curve1" },
352
+    {     "par",      "parabola",                                      0,                    AV_OPT_TYPE_CONST,  {.i64 = PAR  }, 0, 0, FLAGS, "curve1" },
353
+    {     "exp",      "exponential",                                   0,                    AV_OPT_TYPE_CONST,  {.i64 = EXP  }, 0, 0, FLAGS, "curve1" },
354
+    {     "iqsin",    "inverted quarter of sine wave",                 0,                    AV_OPT_TYPE_CONST,  {.i64 = IQSIN}, 0, 0, FLAGS, "curve1" },
355
+    {     "ihsin",    "inverted half of sine wave",                    0,                    AV_OPT_TYPE_CONST,  {.i64 = IHSIN}, 0, 0, FLAGS, "curve1" },
356
+    {     "dese",     "double-exponential seat",                       0,                    AV_OPT_TYPE_CONST,  {.i64 = DESE }, 0, 0, FLAGS, "curve1" },
357
+    {     "desi",     "double-exponential sigmoid",                    0,                    AV_OPT_TYPE_CONST,  {.i64 = DESI }, 0, 0, FLAGS, "curve1" },
358
+    { "curve2",       "set fade curve type for 2nd stream",            OFFSET(curve2),       AV_OPT_TYPE_INT,    {.i64 = TRI  }, 0, NB_CURVES - 1, FLAGS, "curve2" },
359
+    { "c2",           "set fade curve type for 2nd stream",            OFFSET(curve2),       AV_OPT_TYPE_INT,    {.i64 = TRI  }, 0, NB_CURVES - 1, FLAGS, "curve2" },
360
+    {     "tri",      "linear slope",                                  0,                    AV_OPT_TYPE_CONST,  {.i64 = TRI  }, 0, 0, FLAGS, "curve2" },
361
+    {     "qsin",     "quarter of sine wave",                          0,                    AV_OPT_TYPE_CONST,  {.i64 = QSIN }, 0, 0, FLAGS, "curve2" },
362
+    {     "esin",     "exponential sine wave",                         0,                    AV_OPT_TYPE_CONST,  {.i64 = ESIN }, 0, 0, FLAGS, "curve2" },
363
+    {     "hsin",     "half of sine wave",                             0,                    AV_OPT_TYPE_CONST,  {.i64 = HSIN }, 0, 0, FLAGS, "curve2" },
364
+    {     "log",      "logarithmic",                                   0,                    AV_OPT_TYPE_CONST,  {.i64 = LOG  }, 0, 0, FLAGS, "curve2" },
365
+    {     "ipar",     "inverted parabola",                             0,                    AV_OPT_TYPE_CONST,  {.i64 = IPAR }, 0, 0, FLAGS, "curve2" },
366
+    {     "qua",      "quadratic",                                     0,                    AV_OPT_TYPE_CONST,  {.i64 = QUA  }, 0, 0, FLAGS, "curve2" },
367
+    {     "cub",      "cubic",                                         0,                    AV_OPT_TYPE_CONST,  {.i64 = CUB  }, 0, 0, FLAGS, "curve2" },
368
+    {     "squ",      "square root",                                   0,                    AV_OPT_TYPE_CONST,  {.i64 = SQU  }, 0, 0, FLAGS, "curve2" },
369
+    {     "cbr",      "cubic root",                                    0,                    AV_OPT_TYPE_CONST,  {.i64 = CBR  }, 0, 0, FLAGS, "curve2" },
370
+    {     "par",      "parabola",                                      0,                    AV_OPT_TYPE_CONST,  {.i64 = PAR  }, 0, 0, FLAGS, "curve2" },
371
+    {     "exp",      "exponential",                                   0,                    AV_OPT_TYPE_CONST,  {.i64 = EXP  }, 0, 0, FLAGS, "curve2" },
372
+    {     "iqsin",    "inverted quarter of sine wave",                 0,                    AV_OPT_TYPE_CONST,  {.i64 = IQSIN}, 0, 0, FLAGS, "curve2" },
373
+    {     "ihsin",    "inverted half of sine wave",                    0,                    AV_OPT_TYPE_CONST,  {.i64 = IHSIN}, 0, 0, FLAGS, "curve2" },
374
+    {     "dese",     "double-exponential seat",                       0,                    AV_OPT_TYPE_CONST,  {.i64 = DESE }, 0, 0, FLAGS, "curve2" },
375
+    {     "desi",     "double-exponential sigmoid",                    0,                    AV_OPT_TYPE_CONST,  {.i64 = DESI }, 0, 0, FLAGS, "curve2" },
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
+        if (s->overlap) {
485
+            cf[0] = ff_get_audio_buffer(outlink, s->nb_samples);
486
+            cf[1] = ff_get_audio_buffer(outlink, s->nb_samples);
487
+            out = ff_get_audio_buffer(outlink, s->nb_samples);
488
+            if (!out || !cf[0] || !cf[1]) {
489
+                av_frame_free(&out);
490
+                ret = AVERROR(ENOMEM);
491
+                goto fail;
492
+            }
493
+
494
+            av_audio_fifo_read(s->fifo[0], (void **)cf[0]->extended_data, s->nb_samples);
495
+            av_audio_fifo_read(s->fifo[1], (void **)cf[1]->extended_data, s->nb_samples);
496
+
497
+            s->crossfade_samples(out->extended_data, cf[0]->extended_data,
498
+                                 cf[1]->extended_data,
499
+                                 s->nb_samples, av_frame_get_channels(in),
500
+                                 s->curve, s->curve2);
501
+            out->pts = s->pts;
502
+            s->pts += av_rescale_q(s->nb_samples,
503
+                (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
504
+            ret = ff_filter_frame(outlink, out);
505
+            if (ret < 0)
506
+                goto fail;
507
+        } else {
508
+            out = ff_get_audio_buffer(outlink, s->nb_samples);
509
+            cf[1] = ff_get_audio_buffer(outlink, s->nb_samples);
510
+            if (!out || !cf[1]) {
511
+                ret = AVERROR(ENOMEM);
512
+                av_frame_free(&out);
513
+                goto fail;
514
+            }
515
+
516
+            av_audio_fifo_read(s->fifo[1], (void **)cf[1]->extended_data, s->nb_samples);
517
+
518
+            s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples,
519
+                            outlink->channels, 1, 0, s->nb_samples, s->curve2);
520
+            out->pts = s->pts;
521
+            s->pts += av_rescale_q(s->nb_samples,
522
+                (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
523
+            ret = ff_filter_frame(outlink, out);
524
+            if (ret < 0)
525
+                goto fail;
526
+        }
527
+
528
+        nb_samples = av_audio_fifo_size(s->fifo[1]);
529
+        if (nb_samples > 0) {
530
+            out = ff_get_audio_buffer(outlink, nb_samples);
531
+            if (!out) {
532
+                ret = AVERROR(ENOMEM);
533
+                goto fail;
534
+            }
535
+
536
+            av_audio_fifo_read(s->fifo[1], (void **)out->extended_data, nb_samples);
537
+            out->pts = s->pts;
538
+            s->pts += av_rescale_q(nb_samples,
539
+                (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
540
+            ret = ff_filter_frame(outlink, out);
541
+        }
542
+        s->crossfade_is_over = 1;
543
+    }
544
+
545
+fail:
546
+    av_frame_free(&in);
547
+    av_frame_free(&cf[0]);
548
+    av_frame_free(&cf[1]);
549
+    return ret;
550
+}
551
+
552
+static int acrossfade_request_frame(AVFilterLink *outlink)
553
+{
554
+    AVFilterContext *ctx = outlink->src;
555
+    AudioFadeContext *s = ctx->priv;
556
+    int ret = 0;
557
+
558
+    if (!s->cf0_eof) {
559
+        AVFilterLink *cf0 = ctx->inputs[0];
560
+        ret = ff_request_frame(cf0);
561
+        if (ret < 0 && ret != AVERROR_EOF)
562
+            return ret;
563
+        if (ret == AVERROR_EOF) {
564
+            s->cf0_eof = 1;
565
+            ret = 0;
566
+        }
567
+    } else {
568
+        AVFilterLink *cf1 = ctx->inputs[1];
569
+        int nb_samples = av_audio_fifo_size(s->fifo[1]);
570
+
571
+        ret = ff_request_frame(cf1);
572
+        if (ret == AVERROR_EOF && nb_samples > 0) {
573
+            AVFrame *out = ff_get_audio_buffer(outlink, nb_samples);
574
+            if (!out)
575
+                return AVERROR(ENOMEM);
576
+
577
+            av_audio_fifo_read(s->fifo[1], (void **)out->extended_data, nb_samples);
578
+            ret = ff_filter_frame(outlink, out);
579
+        }
580
+    }
581
+
582
+    return ret;
583
+}
584
+
585
+static int acrossfade_config_output(AVFilterLink *outlink)
586
+{
587
+    AVFilterContext *ctx = outlink->src;
588
+    AudioFadeContext *s  = ctx->priv;
589
+
590
+    if (ctx->inputs[0]->sample_rate != ctx->inputs[1]->sample_rate) {
591
+        av_log(ctx, AV_LOG_ERROR,
592
+               "Inputs must have the same sample rate "
593
+               "%d for in0 vs %d for in1\n",
594
+               ctx->inputs[0]->sample_rate, ctx->inputs[1]->sample_rate);
595
+        return AVERROR(EINVAL);
596
+    }
597
+
598
+    outlink->sample_rate = ctx->inputs[0]->sample_rate;
599
+    outlink->time_base   = ctx->inputs[0]->time_base;
600
+    outlink->channel_layout = ctx->inputs[0]->channel_layout;
601
+    outlink->channels = ctx->inputs[0]->channels;
602
+    outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
603
+
604
+    switch (outlink->format) {
605
+    case AV_SAMPLE_FMT_DBL:  s->crossfade_samples = crossfade_samples_dbl;  break;
606
+    case AV_SAMPLE_FMT_DBLP: s->crossfade_samples = crossfade_samples_dblp; break;
607
+    case AV_SAMPLE_FMT_FLT:  s->crossfade_samples = crossfade_samples_flt;  break;
608
+    case AV_SAMPLE_FMT_FLTP: s->crossfade_samples = crossfade_samples_fltp; break;
609
+    case AV_SAMPLE_FMT_S16:  s->crossfade_samples = crossfade_samples_s16;  break;
610
+    case AV_SAMPLE_FMT_S16P: s->crossfade_samples = crossfade_samples_s16p; break;
611
+    case AV_SAMPLE_FMT_S32:  s->crossfade_samples = crossfade_samples_s32;  break;
612
+    case AV_SAMPLE_FMT_S32P: s->crossfade_samples = crossfade_samples_s32p; break;
613
+    }
614
+
615
+    config_output(outlink);
616
+
617
+    s->fifo[0] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->nb_samples);
618
+    s->fifo[1] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->nb_samples);
619
+    if (!s->fifo[0] || !s->fifo[1])
620
+        return AVERROR(ENOMEM);
621
+
622
+    return 0;
623
+}
624
+
625
+static av_cold void uninit(AVFilterContext *ctx)
626
+{
627
+    AudioFadeContext *s = ctx->priv;
628
+
629
+    av_audio_fifo_free(s->fifo[0]);
630
+    av_audio_fifo_free(s->fifo[1]);
631
+}
632
+
633
+static const AVFilterPad avfilter_af_acrossfade_inputs[] = {
634
+    {
635
+        .name         = "crossfade0",
636
+        .type         = AVMEDIA_TYPE_AUDIO,
637
+        .filter_frame = acrossfade_filter_frame,
638
+    },
639
+    {
640
+        .name         = "crossfade1",
641
+        .type         = AVMEDIA_TYPE_AUDIO,
642
+        .filter_frame = acrossfade_filter_frame,
643
+    },
644
+    { NULL }
645
+};
646
+
647
+static const AVFilterPad avfilter_af_acrossfade_outputs[] = {
648
+    {
649
+        .name          = "default",
650
+        .type          = AVMEDIA_TYPE_AUDIO,
651
+        .request_frame = acrossfade_request_frame,
652
+        .config_props  = acrossfade_config_output,
653
+    },
654
+    { NULL }
655
+};
656
+
657
+AVFilter ff_af_acrossfade = {
658
+    .name          = "acrossfade",
659
+    .description   = NULL_IF_CONFIG_SMALL("Cross fade two input audio streams."),
660
+    .query_formats = query_formats,
661
+    .priv_size     = sizeof(AudioFadeContext),
662
+    .uninit        = uninit,
663
+    .priv_class    = &acrossfade_class,
664
+    .inputs        = avfilter_af_acrossfade_inputs,
665
+    .outputs       = avfilter_af_acrossfade_outputs,
666
+};
667
+
668
+#endif /* CONFIG_ACROSSFADE_FILTER */
... ...
@@ -45,6 +45,7 @@ void avfilter_register_all(void)
45 45
         return;
46 46
     initialized = 1;
47 47
 
48
+    REGISTER_FILTER(ACROSSFADE,     acrossfade,     af);
48 49
     REGISTER_FILTER(ADELAY,         adelay,         af);
49 50
     REGISTER_FILTER(AECHO,          aecho,          af);
50 51
     REGISTER_FILTER(AEVAL,          aeval,          af);
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR  5
33
-#define LIBAVFILTER_VERSION_MINOR  29
33
+#define LIBAVFILTER_VERSION_MINOR  30
34 34
 #define LIBAVFILTER_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \