LCOV - code coverage report
Current view: top level - libavfilter - af_afade.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 135 247 54.7 %
Date: 2018-05-20 11:54:08 Functions: 9 23 39.1 %

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

Generated by: LCOV version 1.13