Line | Branch | Exec | Source |
---|---|---|---|
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 "config_components.h" | ||
27 | |||
28 | #include "libavutil/opt.h" | ||
29 | #include "audio.h" | ||
30 | #include "avfilter.h" | ||
31 | #include "filters.h" | ||
32 | #include "internal.h" | ||
33 | |||
34 | typedef struct AudioFadeContext { | ||
35 | const AVClass *class; | ||
36 | int type; | ||
37 | int curve, curve2; | ||
38 | int64_t nb_samples; | ||
39 | int64_t start_sample; | ||
40 | int64_t duration; | ||
41 | int64_t start_time; | ||
42 | double silence; | ||
43 | double unity; | ||
44 | int overlap; | ||
45 | int status[2]; | ||
46 | int passthrough; | ||
47 | int64_t pts; | ||
48 | |||
49 | void (*fade_samples)(uint8_t **dst, uint8_t * const *src, | ||
50 | int nb_samples, int channels, int direction, | ||
51 | int64_t start, int64_t range, int curve, | ||
52 | double silence, double unity); | ||
53 | void (*scale_samples)(uint8_t **dst, uint8_t * const *src, | ||
54 | int nb_samples, int channels, double unity); | ||
55 | void (*crossfade_samples)(uint8_t **dst, uint8_t * const *cf0, | ||
56 | uint8_t * const *cf1, | ||
57 | int nb_samples, int channels, | ||
58 | int curve0, int curve1); | ||
59 | } AudioFadeContext; | ||
60 | |||
61 | enum CurveType { NONE = -1, TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR, PAR, EXP, IQSIN, IHSIN, DESE, DESI, LOSI, SINC, ISINC, QUAT, QUATR, QSIN2, HSIN2, NB_CURVES }; | ||
62 | |||
63 | #define OFFSET(x) offsetof(AudioFadeContext, x) | ||
64 | #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM | ||
65 | #define TFLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM | ||
66 | |||
67 | static const enum AVSampleFormat sample_fmts[] = { | ||
68 | AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, | ||
69 | AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P, | ||
70 | AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, | ||
71 | AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, | ||
72 | AV_SAMPLE_FMT_NONE | ||
73 | }; | ||
74 | |||
75 | 737552 | static double fade_gain(int curve, int64_t index, int64_t range, double silence, double unity) | |
76 | { | ||
77 | #define CUBE(a) ((a)*(a)*(a)) | ||
78 | double gain; | ||
79 | |||
80 | 737552 | gain = av_clipd(1.0 * index / range, 0, 1.0); | |
81 | |||
82 |
6/24✓ Branch 0 taken 90112 times.
✓ Branch 1 taken 90112 times.
✓ Branch 2 taken 90112 times.
✓ Branch 3 taken 90112 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 178312 times.
✓ Branch 6 taken 198792 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
737552 | switch (curve) { |
83 | 90112 | case QSIN: | |
84 | 90112 | gain = sin(gain * M_PI / 2.0); | |
85 | 90112 | break; | |
86 | 90112 | case IQSIN: | |
87 | /* 0.6... = 2 / M_PI */ | ||
88 | 90112 | gain = 0.6366197723675814 * asin(gain); | |
89 | 90112 | break; | |
90 | 90112 | case ESIN: | |
91 | 90112 | gain = 1.0 - cos(M_PI / 4.0 * (CUBE(2.0*gain - 1) + 1)); | |
92 | 90112 | break; | |
93 | 90112 | case HSIN: | |
94 | 90112 | gain = (1.0 - cos(gain * M_PI)) / 2.0; | |
95 | 90112 | break; | |
96 | ✗ | case IHSIN: | |
97 | /* 0.3... = 1 / M_PI */ | ||
98 | ✗ | gain = 0.3183098861837907 * acos(1 - 2 * gain); | |
99 | ✗ | break; | |
100 | 178312 | case EXP: | |
101 | /* -11.5... = 5*ln(0.1) */ | ||
102 | 178312 | gain = exp(-11.512925464970227 * (1 - gain)); | |
103 | 178312 | break; | |
104 | 198792 | case LOG: | |
105 | 198792 | gain = av_clipd(1 + 0.2 * log10(gain), 0, 1.0); | |
106 | 198792 | break; | |
107 | ✗ | case PAR: | |
108 | ✗ | gain = 1 - sqrt(1 - gain); | |
109 | ✗ | break; | |
110 | ✗ | case IPAR: | |
111 | ✗ | gain = (1 - (1 - gain) * (1 - gain)); | |
112 | ✗ | break; | |
113 | ✗ | case QUA: | |
114 | ✗ | gain *= gain; | |
115 | ✗ | break; | |
116 | ✗ | case CUB: | |
117 | ✗ | gain = CUBE(gain); | |
118 | ✗ | break; | |
119 | ✗ | case SQU: | |
120 | ✗ | gain = sqrt(gain); | |
121 | ✗ | break; | |
122 | ✗ | case CBR: | |
123 | ✗ | gain = cbrt(gain); | |
124 | ✗ | break; | |
125 | ✗ | case DESE: | |
126 | ✗ | gain = gain <= 0.5 ? cbrt(2 * gain) / 2: 1 - cbrt(2 * (1 - gain)) / 2; | |
127 | ✗ | break; | |
128 | ✗ | case DESI: | |
129 | ✗ | gain = gain <= 0.5 ? CUBE(2 * gain) / 2: 1 - CUBE(2 * (1 - gain)) / 2; | |
130 | ✗ | break; | |
131 | ✗ | case LOSI: { | |
132 | ✗ | const double a = 1. / (1. - 0.787) - 1; | |
133 | ✗ | double A = 1. / (1.0 + exp(0 -((gain-0.5) * a * 2.0))); | |
134 | ✗ | double B = 1. / (1.0 + exp(a)); | |
135 | ✗ | double C = 1. / (1.0 + exp(0-a)); | |
136 | ✗ | gain = (A - B) / (C - B); | |
137 | } | ||
138 | ✗ | break; | |
139 | ✗ | case SINC: | |
140 | ✗ | gain = gain >= 1.0 ? 1.0 : sin(M_PI * (1.0 - gain)) / (M_PI * (1.0 - gain)); | |
141 | ✗ | break; | |
142 | ✗ | case ISINC: | |
143 | ✗ | gain = gain <= 0.0 ? 0.0 : 1.0 - sin(M_PI * gain) / (M_PI * gain); | |
144 | ✗ | break; | |
145 | ✗ | case QUAT: | |
146 | ✗ | gain = gain * gain * gain * gain; | |
147 | ✗ | break; | |
148 | ✗ | case QUATR: | |
149 | ✗ | gain = pow(gain, 0.25); | |
150 | ✗ | break; | |
151 | ✗ | case QSIN2: | |
152 | ✗ | gain = sin(gain * M_PI / 2.0) * sin(gain * M_PI / 2.0); | |
153 | ✗ | break; | |
154 | ✗ | case HSIN2: | |
155 | ✗ | gain = pow((1.0 - cos(gain * M_PI)) / 2.0, 2.0); | |
156 | ✗ | break; | |
157 | ✗ | case NONE: | |
158 | ✗ | gain = 1.0; | |
159 | ✗ | break; | |
160 | } | ||
161 | |||
162 | 737552 | return silence + (unity - silence) * gain; | |
163 | } | ||
164 | |||
165 | #define FADE_PLANAR(name, type) \ | ||
166 | static void fade_samples_## name ##p(uint8_t **dst, uint8_t * const *src, \ | ||
167 | int nb_samples, int channels, int dir, \ | ||
168 | int64_t start, int64_t range,int curve,\ | ||
169 | double silence, double unity) \ | ||
170 | { \ | ||
171 | int i, c; \ | ||
172 | \ | ||
173 | for (i = 0; i < nb_samples; i++) { \ | ||
174 | double gain = fade_gain(curve, start + i * dir,range,silence,unity);\ | ||
175 | for (c = 0; c < channels; c++) { \ | ||
176 | type *d = (type *)dst[c]; \ | ||
177 | const type *s = (type *)src[c]; \ | ||
178 | \ | ||
179 | d[i] = s[i] * gain; \ | ||
180 | } \ | ||
181 | } \ | ||
182 | } | ||
183 | |||
184 | #define FADE(name, type) \ | ||
185 | static void fade_samples_## name (uint8_t **dst, uint8_t * const *src, \ | ||
186 | int nb_samples, int channels, int dir, \ | ||
187 | int64_t start, int64_t range, int curve, \ | ||
188 | double silence, double unity) \ | ||
189 | { \ | ||
190 | type *d = (type *)dst[0]; \ | ||
191 | const type *s = (type *)src[0]; \ | ||
192 | int i, c, k = 0; \ | ||
193 | \ | ||
194 | for (i = 0; i < nb_samples; i++) { \ | ||
195 | double gain = fade_gain(curve, start + i * dir,range,silence,unity);\ | ||
196 | for (c = 0; c < channels; c++, k++) \ | ||
197 | d[k] = s[k] * gain; \ | ||
198 | } \ | ||
199 | } | ||
200 | |||
201 | ✗ | FADE_PLANAR(dbl, double) | |
202 | ✗ | FADE_PLANAR(flt, float) | |
203 | ✗ | FADE_PLANAR(s16, int16_t) | |
204 | ✗ | FADE_PLANAR(s32, int32_t) | |
205 | |||
206 | ✗ | FADE(dbl, double) | |
207 | ✗ | FADE(flt, float) | |
208 |
4/4✓ Branch 1 taken 1122304 times.
✓ Branch 2 taken 561152 times.
✓ Branch 3 taken 561152 times.
✓ Branch 4 taken 137 times.
|
1683593 | FADE(s16, int16_t) |
209 | ✗ | FADE(s32, int32_t) | |
210 | |||
211 | #define SCALE_PLANAR(name, type) \ | ||
212 | static void scale_samples_## name ##p(uint8_t **dst, uint8_t * const *src, \ | ||
213 | int nb_samples, int channels, \ | ||
214 | double gain) \ | ||
215 | { \ | ||
216 | int i, c; \ | ||
217 | \ | ||
218 | for (i = 0; i < nb_samples; i++) { \ | ||
219 | for (c = 0; c < channels; c++) { \ | ||
220 | type *d = (type *)dst[c]; \ | ||
221 | const type *s = (type *)src[c]; \ | ||
222 | \ | ||
223 | d[i] = s[i] * gain; \ | ||
224 | } \ | ||
225 | } \ | ||
226 | } | ||
227 | |||
228 | #define SCALE(name, type) \ | ||
229 | static void scale_samples_## name (uint8_t **dst, uint8_t * const *src, \ | ||
230 | int nb_samples, int channels, double gain)\ | ||
231 | { \ | ||
232 | type *d = (type *)dst[0]; \ | ||
233 | const type *s = (type *)src[0]; \ | ||
234 | int i, c, k = 0; \ | ||
235 | \ | ||
236 | for (i = 0; i < nb_samples; i++) { \ | ||
237 | for (c = 0; c < channels; c++, k++) \ | ||
238 | d[k] = s[k] * gain; \ | ||
239 | } \ | ||
240 | } | ||
241 | |||
242 | ✗ | SCALE_PLANAR(dbl, double) | |
243 | ✗ | SCALE_PLANAR(flt, float) | |
244 | ✗ | SCALE_PLANAR(s16, int16_t) | |
245 | ✗ | SCALE_PLANAR(s32, int32_t) | |
246 | |||
247 | ✗ | SCALE(dbl, double) | |
248 | ✗ | SCALE(flt, float) | |
249 | ✗ | SCALE(s16, int16_t) | |
250 | ✗ | SCALE(s32, int32_t) | |
251 | |||
252 | 7 | static int config_output(AVFilterLink *outlink) | |
253 | { | ||
254 | 7 | AVFilterContext *ctx = outlink->src; | |
255 | 7 | AudioFadeContext *s = ctx->priv; | |
256 | |||
257 |
1/9✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
7 | switch (outlink->format) { |
258 | ✗ | case AV_SAMPLE_FMT_DBL: s->fade_samples = fade_samples_dbl; | |
259 | ✗ | s->scale_samples = scale_samples_dbl; | |
260 | ✗ | break; | |
261 | ✗ | case AV_SAMPLE_FMT_DBLP: s->fade_samples = fade_samples_dblp; | |
262 | ✗ | s->scale_samples = scale_samples_dblp; | |
263 | ✗ | break; | |
264 | ✗ | case AV_SAMPLE_FMT_FLT: s->fade_samples = fade_samples_flt; | |
265 | ✗ | s->scale_samples = scale_samples_flt; | |
266 | ✗ | break; | |
267 | ✗ | case AV_SAMPLE_FMT_FLTP: s->fade_samples = fade_samples_fltp; | |
268 | ✗ | s->scale_samples = scale_samples_fltp; | |
269 | ✗ | break; | |
270 | 7 | case AV_SAMPLE_FMT_S16: s->fade_samples = fade_samples_s16; | |
271 | 7 | s->scale_samples = scale_samples_s16; | |
272 | 7 | break; | |
273 | ✗ | case AV_SAMPLE_FMT_S16P: s->fade_samples = fade_samples_s16p; | |
274 | ✗ | s->scale_samples = scale_samples_s16p; | |
275 | ✗ | break; | |
276 | ✗ | case AV_SAMPLE_FMT_S32: s->fade_samples = fade_samples_s32; | |
277 | ✗ | s->scale_samples = scale_samples_s32; | |
278 | ✗ | break; | |
279 | ✗ | case AV_SAMPLE_FMT_S32P: s->fade_samples = fade_samples_s32p; | |
280 | ✗ | s->scale_samples = scale_samples_s32p; | |
281 | ✗ | break; | |
282 | } | ||
283 | |||
284 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if (s->duration) |
285 | 7 | s->nb_samples = av_rescale(s->duration, outlink->sample_rate, AV_TIME_BASE); | |
286 | 7 | s->duration = 0; | |
287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (s->start_time) |
288 | ✗ | s->start_sample = av_rescale(s->start_time, outlink->sample_rate, AV_TIME_BASE); | |
289 | 7 | s->start_time = 0; | |
290 | |||
291 | 7 | return 0; | |
292 | } | ||
293 | |||
294 | #if CONFIG_AFADE_FILTER | ||
295 | |||
296 | static const AVOption afade_options[] = { | ||
297 | { "type", "set the fade direction", OFFSET(type), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, TFLAGS, .unit = "type" }, | ||
298 | { "t", "set the fade direction", OFFSET(type), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, TFLAGS, .unit = "type" }, | ||
299 | { "in", "fade-in", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, TFLAGS, .unit = "type" }, | ||
300 | { "out", "fade-out", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, TFLAGS, .unit = "type" }, | ||
301 | { "start_sample", "set number of first sample to start fading", OFFSET(start_sample), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, TFLAGS }, | ||
302 | { "ss", "set number of first sample to start fading", OFFSET(start_sample), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, TFLAGS }, | ||
303 | { "nb_samples", "set number of samples for fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT64, {.i64 = 44100}, 1, INT64_MAX, TFLAGS }, | ||
304 | { "ns", "set number of samples for fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT64, {.i64 = 44100}, 1, INT64_MAX, TFLAGS }, | ||
305 | { "start_time", "set time to start fading", OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0 }, 0, INT64_MAX, TFLAGS }, | ||
306 | { "st", "set time to start fading", OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0 }, 0, INT64_MAX, TFLAGS }, | ||
307 | { "duration", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0 }, 0, INT64_MAX, TFLAGS }, | ||
308 | { "d", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0 }, 0, INT64_MAX, TFLAGS }, | ||
309 | { "curve", "set fade curve type", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, NONE, NB_CURVES - 1, TFLAGS, .unit = "curve" }, | ||
310 | { "c", "set fade curve type", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, NONE, NB_CURVES - 1, TFLAGS, .unit = "curve" }, | ||
311 | { "nofade", "no fade; keep audio as-is", 0, AV_OPT_TYPE_CONST, {.i64 = NONE }, 0, 0, TFLAGS, .unit = "curve" }, | ||
312 | { "tri", "linear slope", 0, AV_OPT_TYPE_CONST, {.i64 = TRI }, 0, 0, TFLAGS, .unit = "curve" }, | ||
313 | { "qsin", "quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = QSIN }, 0, 0, TFLAGS, .unit = "curve" }, | ||
314 | { "esin", "exponential sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = ESIN }, 0, 0, TFLAGS, .unit = "curve" }, | ||
315 | { "hsin", "half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = HSIN }, 0, 0, TFLAGS, .unit = "curve" }, | ||
316 | { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64 = LOG }, 0, 0, TFLAGS, .unit = "curve" }, | ||
317 | { "ipar", "inverted parabola", 0, AV_OPT_TYPE_CONST, {.i64 = IPAR }, 0, 0, TFLAGS, .unit = "curve" }, | ||
318 | { "qua", "quadratic", 0, AV_OPT_TYPE_CONST, {.i64 = QUA }, 0, 0, TFLAGS, .unit = "curve" }, | ||
319 | { "cub", "cubic", 0, AV_OPT_TYPE_CONST, {.i64 = CUB }, 0, 0, TFLAGS, .unit = "curve" }, | ||
320 | { "squ", "square root", 0, AV_OPT_TYPE_CONST, {.i64 = SQU }, 0, 0, TFLAGS, .unit = "curve" }, | ||
321 | { "cbr", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64 = CBR }, 0, 0, TFLAGS, .unit = "curve" }, | ||
322 | { "par", "parabola", 0, AV_OPT_TYPE_CONST, {.i64 = PAR }, 0, 0, TFLAGS, .unit = "curve" }, | ||
323 | { "exp", "exponential", 0, AV_OPT_TYPE_CONST, {.i64 = EXP }, 0, 0, TFLAGS, .unit = "curve" }, | ||
324 | { "iqsin", "inverted quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IQSIN}, 0, 0, TFLAGS, .unit = "curve" }, | ||
325 | { "ihsin", "inverted half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IHSIN}, 0, 0, TFLAGS, .unit = "curve" }, | ||
326 | { "dese", "double-exponential seat", 0, AV_OPT_TYPE_CONST, {.i64 = DESE }, 0, 0, TFLAGS, .unit = "curve" }, | ||
327 | { "desi", "double-exponential sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = DESI }, 0, 0, TFLAGS, .unit = "curve" }, | ||
328 | { "losi", "logistic sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = LOSI }, 0, 0, TFLAGS, .unit = "curve" }, | ||
329 | { "sinc", "sine cardinal function", 0, AV_OPT_TYPE_CONST, {.i64 = SINC }, 0, 0, TFLAGS, .unit = "curve" }, | ||
330 | { "isinc", "inverted sine cardinal function", 0, AV_OPT_TYPE_CONST, {.i64 = ISINC}, 0, 0, TFLAGS, .unit = "curve" }, | ||
331 | { "quat", "quartic", 0, AV_OPT_TYPE_CONST, {.i64 = QUAT }, 0, 0, TFLAGS, .unit = "curve" }, | ||
332 | { "quatr", "quartic root", 0, AV_OPT_TYPE_CONST, {.i64 = QUATR}, 0, 0, TFLAGS, .unit = "curve" }, | ||
333 | { "qsin2", "squared quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = QSIN2}, 0, 0, TFLAGS, .unit = "curve" }, | ||
334 | { "hsin2", "squared half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = HSIN2}, 0, 0, TFLAGS, .unit = "curve" }, | ||
335 | { "silence", "set the silence gain", OFFSET(silence), AV_OPT_TYPE_DOUBLE, {.dbl = 0 }, 0, 1, TFLAGS }, | ||
336 | { "unity", "set the unity gain", OFFSET(unity), AV_OPT_TYPE_DOUBLE, {.dbl = 1 }, 0, 1, TFLAGS }, | ||
337 | { NULL } | ||
338 | }; | ||
339 | |||
340 | AVFILTER_DEFINE_CLASS(afade); | ||
341 | |||
342 | 12 | static av_cold int init(AVFilterContext *ctx) | |
343 | { | ||
344 | 12 | AudioFadeContext *s = ctx->priv; | |
345 | |||
346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (INT64_MAX - s->nb_samples < s->start_sample) |
347 | ✗ | return AVERROR(EINVAL); | |
348 | |||
349 | 12 | return 0; | |
350 | } | ||
351 | |||
352 | 390 | static int filter_frame(AVFilterLink *inlink, AVFrame *buf) | |
353 | { | ||
354 | 390 | AudioFadeContext *s = inlink->dst->priv; | |
355 | 390 | AVFilterLink *outlink = inlink->dst->outputs[0]; | |
356 | 390 | int nb_samples = buf->nb_samples; | |
357 | AVFrame *out_buf; | ||
358 | 390 | int64_t cur_sample = av_rescale_q(buf->pts, inlink->time_base, (AVRational){1, inlink->sample_rate}); | |
359 | |||
360 |
1/2✓ Branch 0 taken 390 times.
✗ Branch 1 not taken.
|
390 | if (s->unity == 1.0 && |
361 |
3/4✓ Branch 0 taken 390 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✓ Branch 3 taken 253 times.
|
390 | ((!s->type && (s->start_sample + s->nb_samples < cur_sample)) || |
362 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
137 | ( s->type && (cur_sample + nb_samples < s->start_sample)))) |
363 | 253 | return ff_filter_frame(outlink, buf); | |
364 | |||
365 |
1/2✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
|
137 | if (av_frame_is_writable(buf)) { |
366 | 137 | out_buf = buf; | |
367 | } else { | ||
368 | ✗ | out_buf = ff_get_audio_buffer(outlink, nb_samples); | |
369 | ✗ | if (!out_buf) | |
370 | ✗ | return AVERROR(ENOMEM); | |
371 | ✗ | av_frame_copy_props(out_buf, buf); | |
372 | } | ||
373 | |||
374 |
2/4✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
|
137 | if ((!s->type && (cur_sample + nb_samples < s->start_sample)) || |
375 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
137 | ( s->type && (s->start_sample + s->nb_samples < cur_sample))) { |
376 | ✗ | if (s->silence == 0.) { | |
377 | ✗ | av_samples_set_silence(out_buf->extended_data, 0, nb_samples, | |
378 | ✗ | out_buf->ch_layout.nb_channels, out_buf->format); | |
379 | } else { | ||
380 | ✗ | s->scale_samples(out_buf->extended_data, buf->extended_data, | |
381 | ✗ | nb_samples, buf->ch_layout.nb_channels, | |
382 | s->silence); | ||
383 | } | ||
384 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
137 | } else if (( s->type && (cur_sample + nb_samples < s->start_sample)) || |
385 |
2/4✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 137 times.
|
137 | (!s->type && (s->start_sample + s->nb_samples < cur_sample))) { |
386 | ✗ | s->scale_samples(out_buf->extended_data, buf->extended_data, | |
387 | ✗ | nb_samples, buf->ch_layout.nb_channels, | |
388 | s->unity); | ||
389 | } else { | ||
390 | int64_t start; | ||
391 | |||
392 |
1/2✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
|
137 | if (!s->type) |
393 | 137 | start = cur_sample - s->start_sample; | |
394 | else | ||
395 | ✗ | start = s->start_sample + s->nb_samples - cur_sample; | |
396 | |||
397 | 137 | s->fade_samples(out_buf->extended_data, buf->extended_data, | |
398 | 137 | nb_samples, buf->ch_layout.nb_channels, | |
399 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
|
137 | s->type ? -1 : 1, start, |
400 | s->nb_samples, s->curve, s->silence, s->unity); | ||
401 | } | ||
402 | |||
403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 137 times.
|
137 | if (buf != out_buf) |
404 | ✗ | av_frame_free(&buf); | |
405 | |||
406 | 137 | return ff_filter_frame(outlink, out_buf); | |
407 | } | ||
408 | |||
409 | ✗ | static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, | |
410 | char *res, int res_len, int flags) | ||
411 | { | ||
412 | int ret; | ||
413 | |||
414 | ✗ | ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags); | |
415 | ✗ | if (ret < 0) | |
416 | ✗ | return ret; | |
417 | |||
418 | ✗ | return config_output(ctx->outputs[0]); | |
419 | } | ||
420 | |||
421 | static const AVFilterPad avfilter_af_afade_inputs[] = { | ||
422 | { | ||
423 | .name = "default", | ||
424 | .type = AVMEDIA_TYPE_AUDIO, | ||
425 | .filter_frame = filter_frame, | ||
426 | }, | ||
427 | }; | ||
428 | |||
429 | static const AVFilterPad avfilter_af_afade_outputs[] = { | ||
430 | { | ||
431 | .name = "default", | ||
432 | .type = AVMEDIA_TYPE_AUDIO, | ||
433 | .config_props = config_output, | ||
434 | }, | ||
435 | }; | ||
436 | |||
437 | const AVFilter ff_af_afade = { | ||
438 | .name = "afade", | ||
439 | .description = NULL_IF_CONFIG_SMALL("Fade in/out input audio."), | ||
440 | .priv_size = sizeof(AudioFadeContext), | ||
441 | .init = init, | ||
442 | FILTER_INPUTS(avfilter_af_afade_inputs), | ||
443 | FILTER_OUTPUTS(avfilter_af_afade_outputs), | ||
444 | FILTER_SAMPLEFMTS_ARRAY(sample_fmts), | ||
445 | .priv_class = &afade_class, | ||
446 | .process_command = process_command, | ||
447 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, | ||
448 | }; | ||
449 | |||
450 | #endif /* CONFIG_AFADE_FILTER */ | ||
451 | |||
452 | #if CONFIG_ACROSSFADE_FILTER | ||
453 | |||
454 | static const AVOption acrossfade_options[] = { | ||
455 | { "nb_samples", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX/10, FLAGS }, | ||
456 | { "ns", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX/10, FLAGS }, | ||
457 | { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0 }, 0, 60000000, FLAGS }, | ||
458 | { "d", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0 }, 0, 60000000, FLAGS }, | ||
459 | { "overlap", "overlap 1st stream end with 2nd stream start", OFFSET(overlap), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, FLAGS }, | ||
460 | { "o", "overlap 1st stream end with 2nd stream start", OFFSET(overlap), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, FLAGS }, | ||
461 | { "curve1", "set fade curve type for 1st stream", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, NONE, NB_CURVES - 1, FLAGS, .unit = "curve" }, | ||
462 | { "c1", "set fade curve type for 1st stream", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, NONE, NB_CURVES - 1, FLAGS, .unit = "curve" }, | ||
463 | { "nofade", "no fade; keep audio as-is", 0, AV_OPT_TYPE_CONST, {.i64 = NONE }, 0, 0, FLAGS, .unit = "curve" }, | ||
464 | { "tri", "linear slope", 0, AV_OPT_TYPE_CONST, {.i64 = TRI }, 0, 0, FLAGS, .unit = "curve" }, | ||
465 | { "qsin", "quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = QSIN }, 0, 0, FLAGS, .unit = "curve" }, | ||
466 | { "esin", "exponential sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = ESIN }, 0, 0, FLAGS, .unit = "curve" }, | ||
467 | { "hsin", "half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = HSIN }, 0, 0, FLAGS, .unit = "curve" }, | ||
468 | { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64 = LOG }, 0, 0, FLAGS, .unit = "curve" }, | ||
469 | { "ipar", "inverted parabola", 0, AV_OPT_TYPE_CONST, {.i64 = IPAR }, 0, 0, FLAGS, .unit = "curve" }, | ||
470 | { "qua", "quadratic", 0, AV_OPT_TYPE_CONST, {.i64 = QUA }, 0, 0, FLAGS, .unit = "curve" }, | ||
471 | { "cub", "cubic", 0, AV_OPT_TYPE_CONST, {.i64 = CUB }, 0, 0, FLAGS, .unit = "curve" }, | ||
472 | { "squ", "square root", 0, AV_OPT_TYPE_CONST, {.i64 = SQU }, 0, 0, FLAGS, .unit = "curve" }, | ||
473 | { "cbr", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64 = CBR }, 0, 0, FLAGS, .unit = "curve" }, | ||
474 | { "par", "parabola", 0, AV_OPT_TYPE_CONST, {.i64 = PAR }, 0, 0, FLAGS, .unit = "curve" }, | ||
475 | { "exp", "exponential", 0, AV_OPT_TYPE_CONST, {.i64 = EXP }, 0, 0, FLAGS, .unit = "curve" }, | ||
476 | { "iqsin", "inverted quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IQSIN}, 0, 0, FLAGS, .unit = "curve" }, | ||
477 | { "ihsin", "inverted half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IHSIN}, 0, 0, FLAGS, .unit = "curve" }, | ||
478 | { "dese", "double-exponential seat", 0, AV_OPT_TYPE_CONST, {.i64 = DESE }, 0, 0, FLAGS, .unit = "curve" }, | ||
479 | { "desi", "double-exponential sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = DESI }, 0, 0, FLAGS, .unit = "curve" }, | ||
480 | { "losi", "logistic sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = LOSI }, 0, 0, FLAGS, .unit = "curve" }, | ||
481 | { "sinc", "sine cardinal function", 0, AV_OPT_TYPE_CONST, {.i64 = SINC }, 0, 0, FLAGS, .unit = "curve" }, | ||
482 | { "isinc", "inverted sine cardinal function", 0, AV_OPT_TYPE_CONST, {.i64 = ISINC}, 0, 0, FLAGS, .unit = "curve" }, | ||
483 | { "quat", "quartic", 0, AV_OPT_TYPE_CONST, {.i64 = QUAT }, 0, 0, FLAGS, .unit = "curve" }, | ||
484 | { "quatr", "quartic root", 0, AV_OPT_TYPE_CONST, {.i64 = QUATR}, 0, 0, FLAGS, .unit = "curve" }, | ||
485 | { "qsin2", "squared quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = QSIN2}, 0, 0, FLAGS, .unit = "curve" }, | ||
486 | { "hsin2", "squared half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = HSIN2}, 0, 0, FLAGS, .unit = "curve" }, | ||
487 | { "curve2", "set fade curve type for 2nd stream", OFFSET(curve2), AV_OPT_TYPE_INT, {.i64 = TRI }, NONE, NB_CURVES - 1, FLAGS, .unit = "curve" }, | ||
488 | { "c2", "set fade curve type for 2nd stream", OFFSET(curve2), AV_OPT_TYPE_INT, {.i64 = TRI }, NONE, NB_CURVES - 1, FLAGS, .unit = "curve" }, | ||
489 | { NULL } | ||
490 | }; | ||
491 | |||
492 | AVFILTER_DEFINE_CLASS(acrossfade); | ||
493 | |||
494 | #define CROSSFADE_PLANAR(name, type) \ | ||
495 | static void crossfade_samples_## name ##p(uint8_t **dst, uint8_t * const *cf0, \ | ||
496 | uint8_t * const *cf1, \ | ||
497 | int nb_samples, int channels, \ | ||
498 | int curve0, int curve1) \ | ||
499 | { \ | ||
500 | int i, c; \ | ||
501 | \ | ||
502 | for (i = 0; i < nb_samples; i++) { \ | ||
503 | double gain0 = fade_gain(curve0, nb_samples - 1 - i, nb_samples,0.,1.);\ | ||
504 | double gain1 = fade_gain(curve1, i, nb_samples, 0., 1.); \ | ||
505 | for (c = 0; c < channels; c++) { \ | ||
506 | type *d = (type *)dst[c]; \ | ||
507 | const type *s0 = (type *)cf0[c]; \ | ||
508 | const type *s1 = (type *)cf1[c]; \ | ||
509 | \ | ||
510 | d[i] = s0[i] * gain0 + s1[i] * gain1; \ | ||
511 | } \ | ||
512 | } \ | ||
513 | } | ||
514 | |||
515 | #define CROSSFADE(name, type) \ | ||
516 | static void crossfade_samples_## name (uint8_t **dst, uint8_t * const *cf0, \ | ||
517 | uint8_t * const *cf1, \ | ||
518 | int nb_samples, int channels, \ | ||
519 | int curve0, int curve1) \ | ||
520 | { \ | ||
521 | type *d = (type *)dst[0]; \ | ||
522 | const type *s0 = (type *)cf0[0]; \ | ||
523 | const type *s1 = (type *)cf1[0]; \ | ||
524 | int i, c, k = 0; \ | ||
525 | \ | ||
526 | for (i = 0; i < nb_samples; i++) { \ | ||
527 | double gain0 = fade_gain(curve0, nb_samples - 1-i,nb_samples,0.,1.);\ | ||
528 | double gain1 = fade_gain(curve1, i, nb_samples, 0., 1.); \ | ||
529 | for (c = 0; c < channels; c++, k++) \ | ||
530 | d[k] = s0[k] * gain0 + s1[k] * gain1; \ | ||
531 | } \ | ||
532 | } | ||
533 | |||
534 | ✗ | CROSSFADE_PLANAR(dbl, double) | |
535 | ✗ | CROSSFADE_PLANAR(flt, float) | |
536 | ✗ | CROSSFADE_PLANAR(s16, int16_t) | |
537 | ✗ | CROSSFADE_PLANAR(s32, int32_t) | |
538 | |||
539 | ✗ | CROSSFADE(dbl, double) | |
540 | ✗ | CROSSFADE(flt, float) | |
541 |
4/4✓ Branch 2 taken 176400 times.
✓ Branch 3 taken 88200 times.
✓ Branch 4 taken 88200 times.
✓ Branch 5 taken 1 times.
|
264601 | CROSSFADE(s16, int16_t) |
542 | ✗ | CROSSFADE(s32, int32_t) | |
543 | |||
544 | 154 | static int check_input(AVFilterLink *inlink) | |
545 | { | ||
546 | 154 | const int queued_samples = ff_inlink_queued_samples(inlink); | |
547 | |||
548 | 154 | return ff_inlink_check_available_samples(inlink, queued_samples + 1) == 1; | |
549 | } | ||
550 | |||
551 | 290 | static int activate(AVFilterContext *ctx) | |
552 | { | ||
553 | 290 | AudioFadeContext *s = ctx->priv; | |
554 | 290 | AVFilterLink *outlink = ctx->outputs[0]; | |
555 | 290 | AVFrame *in = NULL, *out, *cf[2] = { NULL }; | |
556 | 290 | int ret = 0, nb_samples, status; | |
557 | int64_t pts; | ||
558 | |||
559 |
4/4✓ Branch 1 taken 1 times.
✓ Branch 2 taken 289 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
|
292 | FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); |
560 | |||
561 |
4/4✓ Branch 0 taken 284 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 165 times.
✓ Branch 3 taken 119 times.
|
289 | if (s->passthrough && s->status[0]) { |
562 | 165 | ret = ff_inlink_consume_frame(ctx->inputs[1], &in); | |
563 |
2/2✓ Branch 0 taken 82 times.
✓ Branch 1 taken 83 times.
|
165 | if (ret > 0) { |
564 | 82 | in->pts = s->pts; | |
565 | 82 | s->pts += av_rescale_q(in->nb_samples, | |
566 | 82 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); | |
567 | 82 | return ff_filter_frame(outlink, in); | |
568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
|
83 | } else if (ret < 0) { |
569 | ✗ | return ret; | |
570 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 82 times.
|
83 | } else if (ff_inlink_acknowledge_status(ctx->inputs[1], &status, &pts)) { |
571 | 1 | ff_outlink_set_status(outlink, status, pts); | |
572 | 1 | return 0; | |
573 |
1/2✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
|
82 | } else if (!ret) { |
574 |
1/2✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
|
82 | if (ff_outlink_frame_wanted(outlink)) { |
575 | 82 | ff_inlink_request_frame(ctx->inputs[1]); | |
576 | 82 | return 0; | |
577 | } | ||
578 | } | ||
579 | } | ||
580 | |||
581 | 124 | nb_samples = ff_inlink_queued_samples(ctx->inputs[0]); | |
582 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 80 times.
|
124 | if (nb_samples > s->nb_samples) { |
583 | 44 | nb_samples -= s->nb_samples; | |
584 | 44 | s->passthrough = 1; | |
585 | 44 | ret = ff_inlink_consume_samples(ctx->inputs[0], nb_samples, nb_samples, &in); | |
586 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (ret < 0) |
587 | ✗ | return ret; | |
588 | 44 | in->pts = s->pts; | |
589 | 44 | s->pts += av_rescale_q(in->nb_samples, | |
590 | 44 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); | |
591 | 44 | return ff_filter_frame(outlink, in); | |
592 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
80 | } else if (s->status[0] && nb_samples >= s->nb_samples && |
593 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
|
3 | ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) { |
594 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (s->overlap) { |
595 | 1 | out = ff_get_audio_buffer(outlink, s->nb_samples); | |
596 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!out) |
597 | ✗ | return AVERROR(ENOMEM); | |
598 | |||
599 | 1 | ret = ff_inlink_consume_samples(ctx->inputs[0], s->nb_samples, s->nb_samples, &cf[0]); | |
600 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) { |
601 | ✗ | av_frame_free(&out); | |
602 | ✗ | return ret; | |
603 | } | ||
604 | |||
605 | 1 | ret = ff_inlink_consume_samples(ctx->inputs[1], s->nb_samples, s->nb_samples, &cf[1]); | |
606 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) { |
607 | ✗ | av_frame_free(&out); | |
608 | ✗ | return ret; | |
609 | } | ||
610 | |||
611 | 1 | s->crossfade_samples(out->extended_data, cf[0]->extended_data, | |
612 | 1 | cf[1]->extended_data, | |
613 | 1 | s->nb_samples, out->ch_layout.nb_channels, | |
614 | s->curve, s->curve2); | ||
615 | 1 | out->pts = s->pts; | |
616 | 1 | s->pts += av_rescale_q(s->nb_samples, | |
617 | 1 | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); | |
618 | 1 | s->passthrough = 1; | |
619 | 1 | av_frame_free(&cf[0]); | |
620 | 1 | av_frame_free(&cf[1]); | |
621 | 1 | return ff_filter_frame(outlink, out); | |
622 | } else { | ||
623 | ✗ | out = ff_get_audio_buffer(outlink, s->nb_samples); | |
624 | ✗ | if (!out) | |
625 | ✗ | return AVERROR(ENOMEM); | |
626 | |||
627 | ✗ | ret = ff_inlink_consume_samples(ctx->inputs[0], s->nb_samples, s->nb_samples, &cf[0]); | |
628 | ✗ | if (ret < 0) { | |
629 | ✗ | av_frame_free(&out); | |
630 | ✗ | return ret; | |
631 | } | ||
632 | |||
633 | ✗ | s->fade_samples(out->extended_data, cf[0]->extended_data, s->nb_samples, | |
634 | ✗ | outlink->ch_layout.nb_channels, -1, s->nb_samples - 1, s->nb_samples, s->curve, 0., 1.); | |
635 | ✗ | out->pts = s->pts; | |
636 | ✗ | s->pts += av_rescale_q(s->nb_samples, | |
637 | ✗ | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); | |
638 | ✗ | av_frame_free(&cf[0]); | |
639 | ✗ | ret = ff_filter_frame(outlink, out); | |
640 | ✗ | if (ret < 0) | |
641 | ✗ | return ret; | |
642 | |||
643 | ✗ | out = ff_get_audio_buffer(outlink, s->nb_samples); | |
644 | ✗ | if (!out) | |
645 | ✗ | return AVERROR(ENOMEM); | |
646 | |||
647 | ✗ | ret = ff_inlink_consume_samples(ctx->inputs[1], s->nb_samples, s->nb_samples, &cf[1]); | |
648 | ✗ | if (ret < 0) { | |
649 | ✗ | av_frame_free(&out); | |
650 | ✗ | return ret; | |
651 | } | ||
652 | |||
653 | ✗ | s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples, | |
654 | outlink->ch_layout.nb_channels, 1, 0, s->nb_samples, s->curve2, 0., 1.); | ||
655 | ✗ | out->pts = s->pts; | |
656 | ✗ | s->pts += av_rescale_q(s->nb_samples, | |
657 | ✗ | (AVRational){ 1, outlink->sample_rate }, outlink->time_base); | |
658 | ✗ | s->passthrough = 1; | |
659 | ✗ | av_frame_free(&cf[1]); | |
660 | ✗ | return ff_filter_frame(outlink, out); | |
661 | } | ||
662 |
2/2✓ Branch 1 taken 78 times.
✓ Branch 2 taken 1 times.
|
79 | } else if (ff_outlink_frame_wanted(outlink)) { |
663 |
4/4✓ Branch 0 taken 76 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 75 times.
|
78 | if (!s->status[0] && check_input(ctx->inputs[0])) |
664 | 1 | s->status[0] = AVERROR_EOF; | |
665 | 78 | s->passthrough = !s->status[0]; | |
666 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 78 times.
|
78 | if (check_input(ctx->inputs[1])) { |
667 | ✗ | s->status[1] = AVERROR_EOF; | |
668 | ✗ | ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE); | |
669 | ✗ | return 0; | |
670 | } | ||
671 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 3 times.
|
78 | if (!s->status[0]) |
672 | 75 | ff_inlink_request_frame(ctx->inputs[0]); | |
673 | else | ||
674 | 3 | ff_inlink_request_frame(ctx->inputs[1]); | |
675 | 78 | return 0; | |
676 | } | ||
677 | |||
678 | 1 | return ret; | |
679 | } | ||
680 | |||
681 | 1 | static int acrossfade_config_output(AVFilterLink *outlink) | |
682 | { | ||
683 | 1 | AVFilterContext *ctx = outlink->src; | |
684 | 1 | AudioFadeContext *s = ctx->priv; | |
685 | |||
686 | 1 | outlink->time_base = ctx->inputs[0]->time_base; | |
687 | |||
688 |
1/9✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
1 | switch (outlink->format) { |
689 | ✗ | case AV_SAMPLE_FMT_DBL: s->crossfade_samples = crossfade_samples_dbl; break; | |
690 | ✗ | case AV_SAMPLE_FMT_DBLP: s->crossfade_samples = crossfade_samples_dblp; break; | |
691 | ✗ | case AV_SAMPLE_FMT_FLT: s->crossfade_samples = crossfade_samples_flt; break; | |
692 | ✗ | case AV_SAMPLE_FMT_FLTP: s->crossfade_samples = crossfade_samples_fltp; break; | |
693 | 1 | case AV_SAMPLE_FMT_S16: s->crossfade_samples = crossfade_samples_s16; break; | |
694 | ✗ | case AV_SAMPLE_FMT_S16P: s->crossfade_samples = crossfade_samples_s16p; break; | |
695 | ✗ | case AV_SAMPLE_FMT_S32: s->crossfade_samples = crossfade_samples_s32; break; | |
696 | ✗ | case AV_SAMPLE_FMT_S32P: s->crossfade_samples = crossfade_samples_s32p; break; | |
697 | } | ||
698 | |||
699 | 1 | config_output(outlink); | |
700 | |||
701 | 1 | return 0; | |
702 | } | ||
703 | |||
704 | 47 | static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples) | |
705 | { | ||
706 | 47 | AVFilterContext *ctx = inlink->dst; | |
707 | 47 | AudioFadeContext *s = ctx->priv; | |
708 | |||
709 | 47 | return s->passthrough ? | |
710 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 2 times.
|
49 | ff_null_get_audio_buffer (inlink, nb_samples) : |
711 | 2 | ff_default_get_audio_buffer(inlink, nb_samples); | |
712 | } | ||
713 | |||
714 | static const AVFilterPad avfilter_af_acrossfade_inputs[] = { | ||
715 | { | ||
716 | .name = "crossfade0", | ||
717 | .type = AVMEDIA_TYPE_AUDIO, | ||
718 | .get_buffer.audio = get_audio_buffer, | ||
719 | }, | ||
720 | { | ||
721 | .name = "crossfade1", | ||
722 | .type = AVMEDIA_TYPE_AUDIO, | ||
723 | .get_buffer.audio = get_audio_buffer, | ||
724 | }, | ||
725 | }; | ||
726 | |||
727 | static const AVFilterPad avfilter_af_acrossfade_outputs[] = { | ||
728 | { | ||
729 | .name = "default", | ||
730 | .type = AVMEDIA_TYPE_AUDIO, | ||
731 | .config_props = acrossfade_config_output, | ||
732 | }, | ||
733 | }; | ||
734 | |||
735 | const AVFilter ff_af_acrossfade = { | ||
736 | .name = "acrossfade", | ||
737 | .description = NULL_IF_CONFIG_SMALL("Cross fade two input audio streams."), | ||
738 | .priv_size = sizeof(AudioFadeContext), | ||
739 | .activate = activate, | ||
740 | .priv_class = &acrossfade_class, | ||
741 | FILTER_INPUTS(avfilter_af_acrossfade_inputs), | ||
742 | FILTER_OUTPUTS(avfilter_af_acrossfade_outputs), | ||
743 | FILTER_SAMPLEFMTS_ARRAY(sample_fmts), | ||
744 | }; | ||
745 | |||
746 | #endif /* CONFIG_ACROSSFADE_FILTER */ | ||
747 |