2 * Copyright (c) 2013 Paul B Mahol
4 * This file is part of FFmpeg.
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.
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.
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
26 #include "libavutil/opt.h"
40 void (*fade_samples
)(uint8_t **dst
, uint8_t * const *src
,
41 int nb_samples
, int channels
, int direction
,
42 int64_t start
, int range
, int curve
);
45 enum CurveType
{ TRI
, QSIN
, ESIN
, HSIN
, LOG
, PAR
, QUA
, CUB
, SQU
, CBR
};
47 #define OFFSET(x) offsetof(AudioFadeContext, x)
48 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
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
}, TRI
, CBR
, FLAGS
, "curve" },
64 { "c", "set fade curve type", OFFSET(curve
), AV_OPT_TYPE_INT
, {.i64
= TRI
}, TRI
, CBR
, 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 { "par", "inverted parabola", 0, AV_OPT_TYPE_CONST
, {.i64
= PAR
}, 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" },
78 AVFILTER_DEFINE_CLASS(afade
);
80 static av_cold
int init(AVFilterContext
*ctx
)
82 AudioFadeContext
*s
= ctx
->priv
;
84 if (INT64_MAX
- s
->nb_samples
< s
->start_sample
)
85 return AVERROR(EINVAL
);
90 static int query_formats(AVFilterContext
*ctx
)
92 AVFilterFormats
*formats
;
93 AVFilterChannelLayouts
*layouts
;
94 static const enum AVSampleFormat sample_fmts
[] = {
95 AV_SAMPLE_FMT_S16
, AV_SAMPLE_FMT_S16P
,
96 AV_SAMPLE_FMT_S32
, AV_SAMPLE_FMT_S32P
,
97 AV_SAMPLE_FMT_FLT
, AV_SAMPLE_FMT_FLTP
,
98 AV_SAMPLE_FMT_DBL
, AV_SAMPLE_FMT_DBLP
,
102 layouts
= ff_all_channel_layouts();
104 return AVERROR(ENOMEM
);
105 ff_set_common_channel_layouts(ctx
, layouts
);
107 formats
= ff_make_format_list(sample_fmts
);
109 return AVERROR(ENOMEM
);
110 ff_set_common_formats(ctx
, formats
);
112 formats
= ff_all_samplerates();
114 return AVERROR(ENOMEM
);
115 ff_set_common_samplerates(ctx
, formats
);
120 static double fade_gain(int curve
, int64_t index
, int range
)
124 gain
= FFMAX(0.0, FFMIN(1.0, 1.0 * index
/ range
));
128 gain
= sin(gain
* M_PI
/ 2.0);
131 gain
= 1.0 - cos(M_PI
/ 4.0 * (pow(2.0*gain
- 1, 3) + 1));
134 gain
= (1.0 - cos(gain
* M_PI
)) / 2.0;
137 gain
= pow(0.1, (1 - gain
) * 5.0);
140 gain
= (1 - (1 - gain
) * (1 - gain
));
146 gain
= gain
* gain
* gain
;
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, int range, int curve) \
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]; \
172 d[i] = s[i] * gain; \
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, int range, int curve) \
182 type *d = (type *)dst[0]; \
183 const type *s = (type *)src[0]; \
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; \
193 FADE_PLANAR(dbl
, double)
194 FADE_PLANAR(flt
, float)
195 FADE_PLANAR(s16
, int16_t)
196 FADE_PLANAR(s32
, int32_t)
203 static int config_input(AVFilterLink
*inlink
)
205 AVFilterContext
*ctx
= inlink
->dst
;
206 AudioFadeContext
*s
= ctx
->priv
;
208 switch (inlink
->format
) {
209 case AV_SAMPLE_FMT_DBL
: s
->fade_samples
= fade_samples_dbl
; break;
210 case AV_SAMPLE_FMT_DBLP
: s
->fade_samples
= fade_samples_dblp
; break;
211 case AV_SAMPLE_FMT_FLT
: s
->fade_samples
= fade_samples_flt
; break;
212 case AV_SAMPLE_FMT_FLTP
: s
->fade_samples
= fade_samples_fltp
; break;
213 case AV_SAMPLE_FMT_S16
: s
->fade_samples
= fade_samples_s16
; break;
214 case AV_SAMPLE_FMT_S16P
: s
->fade_samples
= fade_samples_s16p
; break;
215 case AV_SAMPLE_FMT_S32
: s
->fade_samples
= fade_samples_s32
; break;
216 case AV_SAMPLE_FMT_S32P
: s
->fade_samples
= fade_samples_s32p
; break;
220 s
->nb_samples
= av_rescale(s
->duration
, inlink
->sample_rate
, AV_TIME_BASE
);
222 s
->start_sample
= av_rescale(s
->start_time
, inlink
->sample_rate
, AV_TIME_BASE
);
227 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*buf
)
229 AudioFadeContext
*s
= inlink
->dst
->priv
;
230 AVFilterLink
*outlink
= inlink
->dst
->outputs
[0];
231 int nb_samples
= buf
->nb_samples
;
233 int64_t cur_sample
= av_rescale_q(buf
->pts
, (AVRational
){1, outlink
->sample_rate
}, outlink
->time_base
);
235 if ((!s
->type
&& (s
->start_sample
+ s
->nb_samples
< cur_sample
)) ||
236 ( s
->type
&& (cur_sample
+ s
->nb_samples
< s
->start_sample
)))
237 return ff_filter_frame(outlink
, buf
);
239 if (av_frame_is_writable(buf
)) {
242 out_buf
= ff_get_audio_buffer(inlink
, nb_samples
);
244 return AVERROR(ENOMEM
);
245 av_frame_copy_props(out_buf
, buf
);
248 if ((!s
->type
&& (cur_sample
+ nb_samples
< s
->start_sample
)) ||
249 ( s
->type
&& (s
->start_sample
+ s
->nb_samples
< cur_sample
))) {
250 av_samples_set_silence(out_buf
->extended_data
, 0, nb_samples
,
251 av_frame_get_channels(out_buf
), out_buf
->format
);
256 start
= cur_sample
- s
->start_sample
;
258 start
= s
->start_sample
+ s
->nb_samples
- cur_sample
;
260 s
->fade_samples(out_buf
->extended_data
, buf
->extended_data
,
261 nb_samples
, av_frame_get_channels(buf
),
262 s
->type
? -1 : 1, start
,
263 s
->nb_samples
, s
->curve
);
269 return ff_filter_frame(outlink
, out_buf
);
272 static const AVFilterPad avfilter_af_afade_inputs
[] = {
275 .type
= AVMEDIA_TYPE_AUDIO
,
276 .filter_frame
= filter_frame
,
277 .config_props
= config_input
,
282 static const AVFilterPad avfilter_af_afade_outputs
[] = {
285 .type
= AVMEDIA_TYPE_AUDIO
,
290 AVFilter ff_af_afade
= {
292 .description
= NULL_IF_CONFIG_SMALL("Fade in/out input audio."),
293 .query_formats
= query_formats
,
294 .priv_size
= sizeof(AudioFadeContext
),
296 .inputs
= avfilter_af_afade_inputs
,
297 .outputs
= avfilter_af_afade_outputs
,
298 .priv_class
= &afade_class
,
299 .flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
,