LCOV - code coverage report
Current view: top level - src/libavfilter - af_afade.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 152 260 58.5 %
Date: 2017-01-24 04:42:20 Functions: 11 25 44.0 %

          Line data    Source code
       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           7 : 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           7 :     layouts = ff_all_channel_counts();
      74           7 :     if (!layouts)
      75           0 :         return AVERROR(ENOMEM);
      76           7 :     ret = ff_set_common_channel_layouts(ctx, layouts);
      77           7 :     if (ret < 0)
      78           0 :         return ret;
      79             : 
      80           7 :     formats = ff_make_format_list(sample_fmts);
      81           7 :     if (!formats)
      82           0 :         return AVERROR(ENOMEM);
      83           7 :     ret = ff_set_common_formats(ctx, formats);
      84           7 :     if (ret < 0)
      85           0 :         return ret;
      86             : 
      87           7 :     formats = ff_all_samplerates();
      88           7 :     if (!formats)
      89           0 :         return AVERROR(ENOMEM);
      90           7 :     return ff_set_common_samplerates(ctx, formats);
      91             : }
      92             : 
      93      732432 : static double fade_gain(int curve, int64_t index, int range)
      94             : {
      95             : #define CUBE(a) ((a)*(a)*(a))
      96             :     double gain;
      97             : 
      98      732432 :     gain = av_clipd(1.0 * index / range, 0, 1.0);
      99             : 
     100      732432 :     switch (curve) {
     101             :     case QSIN:
     102       89088 :         gain = sin(gain * M_PI / 2.0);
     103       89088 :         break;
     104             :     case IQSIN:
     105             :         /* 0.6... = 2 / M_PI */
     106       89088 :         gain = 0.6366197723675814 * asin(gain);
     107       89088 :         break;
     108             :     case ESIN:
     109       89088 :         gain = 1.0 - cos(M_PI / 4.0 * (CUBE(2.0*gain - 1) + 1));
     110       89088 :         break;
     111             :     case HSIN:
     112       89088 :         gain = (1.0 - cos(gain * M_PI)) / 2.0;
     113       89088 :         break;
     114             :     case IHSIN:
     115             :         /* 0.3... = 1 / M_PI */
     116           0 :         gain = 0.3183098861837907 * acos(1 - 2 * gain);
     117           0 :         break;
     118             :     case EXP:
     119             :         /* -11.5... = 5*ln(0.1) */
     120      177288 :         gain = exp(-11.512925464970227 * (1 - gain));
     121      177288 :         break;
     122             :     case LOG:
     123      198792 :         gain = av_clipd(1 + 0.2 * log10(gain), 0, 1.0);
     124      198792 :         break;
     125             :     case PAR:
     126           0 :         gain = 1 - sqrt(1 - gain);
     127           0 :         break;
     128             :     case IPAR:
     129           0 :         gain = (1 - (1 - gain) * (1 - gain));
     130           0 :         break;
     131             :     case QUA:
     132           0 :         gain *= gain;
     133           0 :         break;
     134             :     case CUB:
     135           0 :         gain = CUBE(gain);
     136           0 :         break;
     137             :     case SQU:
     138           0 :         gain = sqrt(gain);
     139           0 :         break;
     140             :     case CBR:
     141           0 :         gain = cbrt(gain);
     142           0 :         break;
     143             :     case DESE:
     144           0 :         gain = gain <= 0.5 ? cbrt(2 * gain) / 2: 1 - cbrt(2 * (1 - gain)) / 2;
     145           0 :         break;
     146             :     case DESI:
     147           0 :         gain = gain <= 0.5 ? CUBE(2 * gain) / 2: 1 - CUBE(2 * (1 - gain)) / 2;
     148           0 :         break;
     149             :     }
     150             : 
     151      732432 :     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           0 : FADE_PLANAR(dbl, double)
     189           0 : FADE_PLANAR(flt, float)
     190           0 : FADE_PLANAR(s16, int16_t)
     191           0 : FADE_PLANAR(s32, int32_t)
     192             : 
     193           0 : FADE(dbl, double)
     194           0 : FADE(flt, float)
     195         543 : FADE(s16, int16_t)
     196           0 : FADE(s32, int32_t)
     197             : 
     198           7 : static int config_output(AVFilterLink *outlink)
     199             : {
     200           7 :     AVFilterContext *ctx = outlink->src;
     201           7 :     AudioFadeContext *s  = ctx->priv;
     202             : 
     203           7 :     switch (outlink->format) {
     204           0 :     case AV_SAMPLE_FMT_DBL:  s->fade_samples = fade_samples_dbl;  break;
     205           0 :     case AV_SAMPLE_FMT_DBLP: s->fade_samples = fade_samples_dblp; break;
     206           0 :     case AV_SAMPLE_FMT_FLT:  s->fade_samples = fade_samples_flt;  break;
     207           0 :     case AV_SAMPLE_FMT_FLTP: s->fade_samples = fade_samples_fltp; break;
     208           7 :     case AV_SAMPLE_FMT_S16:  s->fade_samples = fade_samples_s16;  break;
     209           0 :     case AV_SAMPLE_FMT_S16P: s->fade_samples = fade_samples_s16p; break;
     210           0 :     case AV_SAMPLE_FMT_S32:  s->fade_samples = fade_samples_s32;  break;
     211           0 :     case AV_SAMPLE_FMT_S32P: s->fade_samples = fade_samples_s32p; break;
     212             :     }
     213             : 
     214           7 :     if (s->duration)
     215           7 :         s->nb_samples = av_rescale(s->duration, outlink->sample_rate, AV_TIME_BASE);
     216           7 :     if (s->start_time)
     217           0 :         s->start_sample = av_rescale(s->start_time, outlink->sample_rate, AV_TIME_BASE);
     218             : 
     219           7 :     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           6 : static av_cold int init(AVFilterContext *ctx)
     261             : {
     262           6 :     AudioFadeContext *s = ctx->priv;
     263             : 
     264           6 :     if (INT64_MAX - s->nb_samples < s->start_sample)
     265           0 :         return AVERROR(EINVAL);
     266             : 
     267           6 :     return 0;
     268             : }
     269             : 
     270        1554 : static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     271             : {
     272        1554 :     AudioFadeContext *s     = inlink->dst->priv;
     273        1554 :     AVFilterLink *outlink   = inlink->dst->outputs[0];
     274        1554 :     int nb_samples          = buf->nb_samples;
     275             :     AVFrame *out_buf;
     276        1554 :     int64_t cur_sample = av_rescale_q(buf->pts, inlink->time_base, (AVRational){1, inlink->sample_rate});
     277             : 
     278        2097 :     if ((!s->type && (s->start_sample + s->nb_samples < cur_sample)) ||
     279         543 :         ( s->type && (cur_sample + nb_samples < s->start_sample)))
     280        1011 :         return ff_filter_frame(outlink, buf);
     281             : 
     282         543 :     if (av_frame_is_writable(buf)) {
     283         543 :         out_buf = buf;
     284             :     } else {
     285           0 :         out_buf = ff_get_audio_buffer(inlink, nb_samples);
     286           0 :         if (!out_buf)
     287           0 :             return AVERROR(ENOMEM);
     288           0 :         av_frame_copy_props(out_buf, buf);
     289             :     }
     290             : 
     291        1086 :     if ((!s->type && (cur_sample + nb_samples < s->start_sample)) ||
     292         543 :         ( s->type && (s->start_sample + s->nb_samples < cur_sample))) {
     293           0 :         av_samples_set_silence(out_buf->extended_data, 0, nb_samples,
     294           0 :                                av_frame_get_channels(out_buf), out_buf->format);
     295             :     } else {
     296             :         int64_t start;
     297             : 
     298         543 :         if (!s->type)
     299         543 :             start = cur_sample - s->start_sample;
     300             :         else
     301           0 :             start = s->start_sample + s->nb_samples - cur_sample;
     302             : 
     303        1086 :         s->fade_samples(out_buf->extended_data, buf->extended_data,
     304             :                         nb_samples, av_frame_get_channels(buf),
     305         543 :                         s->type ? -1 : 1, start,
     306             :                         s->nb_samples, s->curve);
     307             :     }
     308             : 
     309         543 :     if (buf != out_buf)
     310           0 :         av_frame_free(&buf);
     311             : 
     312         543 :     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           0 : CROSSFADE_PLANAR(dbl, double)
     422           0 : CROSSFADE_PLANAR(flt, float)
     423           0 : CROSSFADE_PLANAR(s16, int16_t)
     424           0 : CROSSFADE_PLANAR(s32, int32_t)
     425             : 
     426           0 : CROSSFADE(dbl, double)
     427           0 : CROSSFADE(flt, float)
     428           1 : CROSSFADE(s16, int16_t)
     429           0 : CROSSFADE(s32, int32_t)
     430             : 
     431         669 : static int acrossfade_filter_frame(AVFilterLink *inlink, AVFrame *in)
     432             : {
     433         669 :     AVFilterContext *ctx  = inlink->dst;
     434         669 :     AudioFadeContext *s   = ctx->priv;
     435         669 :     AVFilterLink *outlink = ctx->outputs[0];
     436         669 :     AVFrame *out, *cf[2] = { NULL };
     437         669 :     int ret = 0, nb_samples;
     438             : 
     439         669 :     if (s->crossfade_is_over) {
     440         322 :         in->pts = s->pts;
     441         322 :         s->pts += av_rescale_q(in->nb_samples,
     442         322 :             (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
     443         322 :         return ff_filter_frame(outlink, in);
     444         347 :     } else if (inlink == ctx->inputs[0]) {
     445         259 :         av_audio_fifo_write(s->fifo[0], (void **)in->extended_data, in->nb_samples);
     446             : 
     447         259 :         nb_samples = av_audio_fifo_size(s->fifo[0]) - s->nb_samples;
     448         259 :         if (nb_samples > 0) {
     449         173 :             out = ff_get_audio_buffer(outlink, nb_samples);
     450         173 :             if (!out) {
     451           0 :                 ret = AVERROR(ENOMEM);
     452           0 :                 goto fail;
     453             :             }
     454         173 :             av_audio_fifo_read(s->fifo[0], (void **)out->extended_data, nb_samples);
     455         173 :             out->pts = s->pts;
     456         173 :             s->pts += av_rescale_q(nb_samples,
     457         173 :                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
     458         173 :             ret = ff_filter_frame(outlink, out);
     459             :         }
     460          88 :     } else if (av_audio_fifo_size(s->fifo[1]) < s->nb_samples) {
     461          87 :         if (!s->overlap && av_audio_fifo_size(s->fifo[0]) > 0) {
     462           0 :             nb_samples = av_audio_fifo_size(s->fifo[0]);
     463             : 
     464           0 :             cf[0] = ff_get_audio_buffer(outlink, nb_samples);
     465           0 :             out = ff_get_audio_buffer(outlink, nb_samples);
     466           0 :             if (!out || !cf[0]) {
     467           0 :                 ret = AVERROR(ENOMEM);
     468           0 :                 goto fail;
     469             :             }
     470           0 :             av_audio_fifo_read(s->fifo[0], (void **)cf[0]->extended_data, nb_samples);
     471             : 
     472           0 :             s->fade_samples(out->extended_data, cf[0]->extended_data, nb_samples,
     473           0 :                             outlink->channels, -1, nb_samples - 1, nb_samples, s->curve);
     474           0 :             out->pts = s->pts;
     475           0 :             s->pts += av_rescale_q(nb_samples,
     476           0 :                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
     477           0 :             ret = ff_filter_frame(outlink, out);
     478           0 :             if (ret < 0)
     479           0 :                 goto fail;
     480             :         }
     481             : 
     482          87 :         av_audio_fifo_write(s->fifo[1], (void **)in->extended_data, in->nb_samples);
     483           1 :     } else if (av_audio_fifo_size(s->fifo[1]) >= s->nb_samples) {
     484           1 :         av_audio_fifo_write(s->fifo[1], (void **)in->extended_data, in->nb_samples);
     485             : 
     486           1 :         if (s->overlap) {
     487           1 :             cf[0] = ff_get_audio_buffer(outlink, s->nb_samples);
     488           1 :             cf[1] = ff_get_audio_buffer(outlink, s->nb_samples);
     489           1 :             out = ff_get_audio_buffer(outlink, s->nb_samples);
     490           1 :             if (!out || !cf[0] || !cf[1]) {
     491           0 :                 av_frame_free(&out);
     492           0 :                 ret = AVERROR(ENOMEM);
     493           0 :                 goto fail;
     494             :             }
     495             : 
     496           1 :             av_audio_fifo_read(s->fifo[0], (void **)cf[0]->extended_data, s->nb_samples);
     497           1 :             av_audio_fifo_read(s->fifo[1], (void **)cf[1]->extended_data, s->nb_samples);
     498             : 
     499           2 :             s->crossfade_samples(out->extended_data, cf[0]->extended_data,
     500           1 :                                  cf[1]->extended_data,
     501             :                                  s->nb_samples, av_frame_get_channels(in),
     502             :                                  s->curve, s->curve2);
     503           1 :             out->pts = s->pts;
     504           1 :             s->pts += av_rescale_q(s->nb_samples,
     505           1 :                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
     506           1 :             ret = ff_filter_frame(outlink, out);
     507           1 :             if (ret < 0)
     508           0 :                 goto fail;
     509             :         } else {
     510           0 :             out = ff_get_audio_buffer(outlink, s->nb_samples);
     511           0 :             cf[1] = ff_get_audio_buffer(outlink, s->nb_samples);
     512           0 :             if (!out || !cf[1]) {
     513           0 :                 ret = AVERROR(ENOMEM);
     514           0 :                 av_frame_free(&out);
     515           0 :                 goto fail;
     516             :             }
     517             : 
     518           0 :             av_audio_fifo_read(s->fifo[1], (void **)cf[1]->extended_data, s->nb_samples);
     519             : 
     520           0 :             s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples,
     521             :                             outlink->channels, 1, 0, s->nb_samples, s->curve2);
     522           0 :             out->pts = s->pts;
     523           0 :             s->pts += av_rescale_q(s->nb_samples,
     524           0 :                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
     525           0 :             ret = ff_filter_frame(outlink, out);
     526           0 :             if (ret < 0)
     527           0 :                 goto fail;
     528             :         }
     529             : 
     530           1 :         nb_samples = av_audio_fifo_size(s->fifo[1]);
     531           1 :         if (nb_samples > 0) {
     532           1 :             out = ff_get_audio_buffer(outlink, nb_samples);
     533           1 :             if (!out) {
     534           0 :                 ret = AVERROR(ENOMEM);
     535           0 :                 goto fail;
     536             :             }
     537             : 
     538           1 :             av_audio_fifo_read(s->fifo[1], (void **)out->extended_data, nb_samples);
     539           1 :             out->pts = s->pts;
     540           1 :             s->pts += av_rescale_q(nb_samples,
     541           1 :                 (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
     542           1 :             ret = ff_filter_frame(outlink, out);
     543             :         }
     544           1 :         s->crossfade_is_over = 1;
     545             :     }
     546             : 
     547             : fail:
     548         347 :     av_frame_free(&in);
     549         347 :     av_frame_free(&cf[0]);
     550         347 :     av_frame_free(&cf[1]);
     551         347 :     return ret;
     552             : }
     553             : 
     554         673 : static int acrossfade_request_frame(AVFilterLink *outlink)
     555             : {
     556         673 :     AVFilterContext *ctx = outlink->src;
     557         673 :     AudioFadeContext *s = ctx->priv;
     558         673 :     int ret = 0;
     559             : 
     560         673 :     if (!s->cf0_eof) {
     561         261 :         AVFilterLink *cf0 = ctx->inputs[0];
     562         261 :         ret = ff_request_frame(cf0);
     563         261 :         if (ret < 0 && ret != AVERROR_EOF)
     564           0 :             return ret;
     565         261 :         if (ret == AVERROR_EOF) {
     566           1 :             s->cf0_eof = 1;
     567           1 :             ret = 0;
     568             :         }
     569             :     } else {
     570         412 :         AVFilterLink *cf1 = ctx->inputs[1];
     571         412 :         int nb_samples = av_audio_fifo_size(s->fifo[1]);
     572             : 
     573         412 :         ret = ff_request_frame(cf1);
     574         412 :         if (ret == AVERROR_EOF && nb_samples > 0) {
     575           0 :             AVFrame *out = ff_get_audio_buffer(outlink, nb_samples);
     576           0 :             if (!out)
     577           0 :                 return AVERROR(ENOMEM);
     578             : 
     579           0 :             av_audio_fifo_read(s->fifo[1], (void **)out->extended_data, nb_samples);
     580           0 :             ret = ff_filter_frame(outlink, out);
     581             :         }
     582             :     }
     583             : 
     584         673 :     return ret;
     585             : }
     586             : 
     587           1 : static int acrossfade_config_output(AVFilterLink *outlink)
     588             : {
     589           1 :     AVFilterContext *ctx = outlink->src;
     590           1 :     AudioFadeContext *s  = ctx->priv;
     591             : 
     592           1 :     if (ctx->inputs[0]->sample_rate != ctx->inputs[1]->sample_rate) {
     593           0 :         av_log(ctx, AV_LOG_ERROR,
     594             :                "Inputs must have the same sample rate "
     595             :                "%d for in0 vs %d for in1\n",
     596           0 :                ctx->inputs[0]->sample_rate, ctx->inputs[1]->sample_rate);
     597           0 :         return AVERROR(EINVAL);
     598             :     }
     599             : 
     600           1 :     outlink->sample_rate = ctx->inputs[0]->sample_rate;
     601           1 :     outlink->time_base   = ctx->inputs[0]->time_base;
     602           1 :     outlink->channel_layout = ctx->inputs[0]->channel_layout;
     603           1 :     outlink->channels = ctx->inputs[0]->channels;
     604             : 
     605           1 :     switch (outlink->format) {
     606           0 :     case AV_SAMPLE_FMT_DBL:  s->crossfade_samples = crossfade_samples_dbl;  break;
     607           0 :     case AV_SAMPLE_FMT_DBLP: s->crossfade_samples = crossfade_samples_dblp; break;
     608           0 :     case AV_SAMPLE_FMT_FLT:  s->crossfade_samples = crossfade_samples_flt;  break;
     609           0 :     case AV_SAMPLE_FMT_FLTP: s->crossfade_samples = crossfade_samples_fltp; break;
     610           1 :     case AV_SAMPLE_FMT_S16:  s->crossfade_samples = crossfade_samples_s16;  break;
     611           0 :     case AV_SAMPLE_FMT_S16P: s->crossfade_samples = crossfade_samples_s16p; break;
     612           0 :     case AV_SAMPLE_FMT_S32:  s->crossfade_samples = crossfade_samples_s32;  break;
     613           0 :     case AV_SAMPLE_FMT_S32P: s->crossfade_samples = crossfade_samples_s32p; break;
     614             :     }
     615             : 
     616           1 :     config_output(outlink);
     617             : 
     618           1 :     s->fifo[0] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->nb_samples);
     619           1 :     s->fifo[1] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->nb_samples);
     620           1 :     if (!s->fifo[0] || !s->fifo[1])
     621           0 :         return AVERROR(ENOMEM);
     622             : 
     623           1 :     return 0;
     624             : }
     625             : 
     626           2 : static av_cold void uninit(AVFilterContext *ctx)
     627             : {
     628           2 :     AudioFadeContext *s = ctx->priv;
     629             : 
     630           2 :     av_audio_fifo_free(s->fifo[0]);
     631           2 :     av_audio_fifo_free(s->fifo[1]);
     632           2 : }
     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 */

Generated by: LCOV version 1.12