]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_xfade.c
avutil/opt: check return value of av_bprint_finalize()
[ffmpeg] / libavfilter / vf_xfade.c
1 /*
2  * Copyright (c) 2020 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 #include "libavutil/imgutils.h"
22 #include "libavutil/eval.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/pixfmt.h"
25 #include "avfilter.h"
26 #include "formats.h"
27 #include "internal.h"
28 #include "filters.h"
29 #include "video.h"
30
31 enum XFadeTransitions {
32     CUSTOM = -1,
33     FADE,
34     WIPELEFT,
35     WIPERIGHT,
36     WIPEUP,
37     WIPEDOWN,
38     SLIDELEFT,
39     SLIDERIGHT,
40     SLIDEUP,
41     SLIDEDOWN,
42     CIRCLECROP,
43     RECTCROP,
44     DISTANCE,
45     FADEBLACK,
46     FADEWHITE,
47     RADIAL,
48     SMOOTHLEFT,
49     SMOOTHRIGHT,
50     SMOOTHUP,
51     SMOOTHDOWN,
52     CIRCLEOPEN,
53     CIRCLECLOSE,
54     VERTOPEN,
55     VERTCLOSE,
56     HORZOPEN,
57     HORZCLOSE,
58     DISSOLVE,
59     PIXELIZE,
60     DIAGTL,
61     DIAGTR,
62     DIAGBL,
63     DIAGBR,
64     HLSLICE,
65     HRSLICE,
66     VUSLICE,
67     VDSLICE,
68     NB_TRANSITIONS,
69 };
70
71 typedef struct XFadeContext {
72     const AVClass *class;
73
74     int     transition;
75     int64_t duration;
76     int64_t offset;
77     char   *custom_str;
78
79     int nb_planes;
80     int depth;
81
82     int64_t duration_pts;
83     int64_t offset_pts;
84     int64_t first_pts;
85     int64_t last_pts;
86     int64_t pts;
87     int xfade_is_over;
88     int need_second;
89     int eof[2];
90     AVFrame *xf[2];
91     int max_value;
92     uint16_t black[4];
93     uint16_t white[4];
94
95     void (*transitionf)(AVFilterContext *ctx, const AVFrame *a, const AVFrame *b, AVFrame *out, float progress,
96                         int slice_start, int slice_end, int jobnr);
97
98     AVExpr *e;
99 } XFadeContext;
100
101 static const char *const var_names[] = {   "X",   "Y",   "W",   "H",   "A",   "B",   "PLANE",          "P",        NULL };
102 enum                                   { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_A, VAR_B, VAR_PLANE, VAR_PROGRESS, VAR_VARS_NB };
103
104 typedef struct ThreadData {
105     const AVFrame *xf[2];
106     AVFrame *out;
107     float progress;
108 } ThreadData;
109
110 static int query_formats(AVFilterContext *ctx)
111 {
112     static const enum AVPixelFormat pix_fmts[] = {
113         AV_PIX_FMT_YUVA444P,
114         AV_PIX_FMT_YUVJ444P,
115         AV_PIX_FMT_YUV444P,
116         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8,
117         AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_GBRP9,
118         AV_PIX_FMT_YUV444P10,
119         AV_PIX_FMT_YUVA444P10,
120         AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GRAY10,
121         AV_PIX_FMT_YUV444P12,
122         AV_PIX_FMT_YUVA444P12,
123         AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GRAY12,
124         AV_PIX_FMT_YUV444P14, AV_PIX_FMT_GBRP14,
125         AV_PIX_FMT_YUV444P16,
126         AV_PIX_FMT_YUVA444P16,
127         AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_GRAY16,
128         AV_PIX_FMT_NONE
129     };
130
131     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
132     if (!fmts_list)
133         return AVERROR(ENOMEM);
134     return ff_set_common_formats(ctx, fmts_list);
135 }
136
137 static av_cold void uninit(AVFilterContext *ctx)
138 {
139     XFadeContext *s = ctx->priv;
140
141     av_expr_free(s->e);
142 }
143
144 #define OFFSET(x) offsetof(XFadeContext, x)
145 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
146
147 static const AVOption xfade_options[] = {
148     { "transition", "set cross fade transition", OFFSET(transition), AV_OPT_TYPE_INT, {.i64=FADE}, -1, NB_TRANSITIONS-1, FLAGS, "transition" },
149     {   "custom",    "custom transition",     0, AV_OPT_TYPE_CONST, {.i64=CUSTOM},    0, 0, FLAGS, "transition" },
150     {   "fade",      "fade transition",       0, AV_OPT_TYPE_CONST, {.i64=FADE},      0, 0, FLAGS, "transition" },
151     {   "wipeleft",  "wipe left transition",  0, AV_OPT_TYPE_CONST, {.i64=WIPELEFT},  0, 0, FLAGS, "transition" },
152     {   "wiperight", "wipe right transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPERIGHT}, 0, 0, FLAGS, "transition" },
153     {   "wipeup",    "wipe up transition",    0, AV_OPT_TYPE_CONST, {.i64=WIPEUP},    0, 0, FLAGS, "transition" },
154     {   "wipedown",  "wipe down transition",  0, AV_OPT_TYPE_CONST, {.i64=WIPEDOWN},  0, 0, FLAGS, "transition" },
155     {   "slideleft",  "slide left transition",  0, AV_OPT_TYPE_CONST, {.i64=SLIDELEFT},  0, 0, FLAGS, "transition" },
156     {   "slideright", "slide right transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDERIGHT}, 0, 0, FLAGS, "transition" },
157     {   "slideup",    "slide up transition",    0, AV_OPT_TYPE_CONST, {.i64=SLIDEUP},    0, 0, FLAGS, "transition" },
158     {   "slidedown",  "slide down transition",  0, AV_OPT_TYPE_CONST, {.i64=SLIDEDOWN},  0, 0, FLAGS, "transition" },
159     {   "circlecrop", "circle crop transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLECROP}, 0, 0, FLAGS, "transition" },
160     {   "rectcrop",   "rect crop transition",   0, AV_OPT_TYPE_CONST, {.i64=RECTCROP},   0, 0, FLAGS, "transition" },
161     {   "distance",   "distance transition",    0, AV_OPT_TYPE_CONST, {.i64=DISTANCE},   0, 0, FLAGS, "transition" },
162     {   "fadeblack",  "fadeblack transition",   0, AV_OPT_TYPE_CONST, {.i64=FADEBLACK},  0, 0, FLAGS, "transition" },
163     {   "fadewhite",  "fadewhite transition",   0, AV_OPT_TYPE_CONST, {.i64=FADEWHITE},  0, 0, FLAGS, "transition" },
164     {   "radial",     "radial transition",      0, AV_OPT_TYPE_CONST, {.i64=RADIAL},     0, 0, FLAGS, "transition" },
165     {   "smoothleft", "smoothleft transition",  0, AV_OPT_TYPE_CONST, {.i64=SMOOTHLEFT}, 0, 0, FLAGS, "transition" },
166     {   "smoothright","smoothright transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHRIGHT},0, 0, FLAGS, "transition" },
167     {   "smoothup",   "smoothup transition",    0, AV_OPT_TYPE_CONST, {.i64=SMOOTHUP},   0, 0, FLAGS, "transition" },
168     {   "smoothdown", "smoothdown transition",  0, AV_OPT_TYPE_CONST, {.i64=SMOOTHDOWN}, 0, 0, FLAGS, "transition" },
169     {   "circleopen", "circleopen transition",  0, AV_OPT_TYPE_CONST, {.i64=CIRCLEOPEN}, 0, 0, FLAGS, "transition" },
170     {   "circleclose","circleclose transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLECLOSE},0, 0, FLAGS, "transition" },
171     {   "vertopen",   "vert open transition",   0, AV_OPT_TYPE_CONST, {.i64=VERTOPEN},   0, 0, FLAGS, "transition" },
172     {   "vertclose",  "vert close transition",  0, AV_OPT_TYPE_CONST, {.i64=VERTCLOSE},  0, 0, FLAGS, "transition" },
173     {   "horzopen",   "horz open transition",   0, AV_OPT_TYPE_CONST, {.i64=HORZOPEN},   0, 0, FLAGS, "transition" },
174     {   "horzclose",  "horz close transition",  0, AV_OPT_TYPE_CONST, {.i64=HORZCLOSE},  0, 0, FLAGS, "transition" },
175     {   "dissolve",   "dissolve transition",    0, AV_OPT_TYPE_CONST, {.i64=DISSOLVE},   0, 0, FLAGS, "transition" },
176     {   "pixelize",   "pixelize transition",    0, AV_OPT_TYPE_CONST, {.i64=PIXELIZE},   0, 0, FLAGS, "transition" },
177     {   "diagtl",     "diag tl transition",     0, AV_OPT_TYPE_CONST, {.i64=DIAGTL},     0, 0, FLAGS, "transition" },
178     {   "diagtr",     "diag tr transition",     0, AV_OPT_TYPE_CONST, {.i64=DIAGTR},     0, 0, FLAGS, "transition" },
179     {   "diagbl",     "diag bl transition",     0, AV_OPT_TYPE_CONST, {.i64=DIAGBL},     0, 0, FLAGS, "transition" },
180     {   "diagbr",     "diag br transition",     0, AV_OPT_TYPE_CONST, {.i64=DIAGBR},     0, 0, FLAGS, "transition" },
181     {   "hlslice",    "hl slice transition",    0, AV_OPT_TYPE_CONST, {.i64=HLSLICE},    0, 0, FLAGS, "transition" },
182     {   "hrslice",    "hr slice transition",    0, AV_OPT_TYPE_CONST, {.i64=HRSLICE},    0, 0, FLAGS, "transition" },
183     {   "vuslice",    "vu slice transition",    0, AV_OPT_TYPE_CONST, {.i64=VUSLICE},    0, 0, FLAGS, "transition" },
184     {   "vdslice",    "vd slice transition",    0, AV_OPT_TYPE_CONST, {.i64=VDSLICE},    0, 0, FLAGS, "transition" },
185     { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=1000000}, 0, 60000000, FLAGS },
186     { "offset",   "set cross fade start relative to first input stream", OFFSET(offset), AV_OPT_TYPE_DURATION, {.i64=0}, INT64_MIN, INT64_MAX, FLAGS },
187     { "expr",   "set expression for custom transition", OFFSET(custom_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
188     { NULL }
189 };
190
191 AVFILTER_DEFINE_CLASS(xfade);
192
193 #define CUSTOM_TRANSITION(name, type, div)                                           \
194 static void custom##name##_transition(AVFilterContext *ctx,                          \
195                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
196                             float progress,                                          \
197                             int slice_start, int slice_end, int jobnr)               \
198 {                                                                                    \
199     XFadeContext *s = ctx->priv;                                                     \
200     const int height = slice_end - slice_start;                                      \
201                                                                                      \
202     double values[VAR_VARS_NB];                                                      \
203     values[VAR_W] = out->width;                                                      \
204     values[VAR_H] = out->height;                                                     \
205     values[VAR_PROGRESS] = progress;                                                 \
206                                                                                      \
207     for (int p = 0; p < s->nb_planes; p++) {                                         \
208         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
209         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
210         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
211                                                                                      \
212         values[VAR_PLANE] = p;                                                       \
213                                                                                      \
214         for (int y = 0; y < height; y++) {                                           \
215             values[VAR_Y] = slice_start + y;                                         \
216             for (int x = 0; x < out->width; x++) {                                   \
217                 values[VAR_X] = x;                                                   \
218                 values[VAR_A] = xf0[x];                                              \
219                 values[VAR_B] = xf1[x];                                              \
220                 dst[x] = av_expr_eval(s->e, values, s);                              \
221             }                                                                        \
222                                                                                      \
223             dst += out->linesize[p] / div;                                           \
224             xf0 += a->linesize[p] / div;                                             \
225             xf1 += b->linesize[p] / div;                                             \
226         }                                                                            \
227     }                                                                                \
228 }
229
230 CUSTOM_TRANSITION(8, uint8_t, 1)
231 CUSTOM_TRANSITION(16, uint16_t, 2)
232
233 static inline float mix(float a, float b, float mix)
234 {
235     return a * mix + b * (1.f - mix);
236 }
237
238 static inline float fract(float a)
239 {
240     return a - floorf(a);
241 }
242
243 static inline float smoothstep(float edge0, float edge1, float x)
244 {
245     float t;
246
247     t = av_clipf((x - edge0) / (edge1 - edge0), 0.f, 1.f);
248
249     return t * t * (3.f - 2.f * t);
250 }
251
252 #define FADE_TRANSITION(name, type, div)                                             \
253 static void fade##name##_transition(AVFilterContext *ctx,                            \
254                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
255                             float progress,                                          \
256                             int slice_start, int slice_end, int jobnr)               \
257 {                                                                                    \
258     XFadeContext *s = ctx->priv;                                                     \
259     const int height = slice_end - slice_start;                                      \
260                                                                                      \
261     for (int p = 0; p < s->nb_planes; p++) {                                         \
262         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
263         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
264         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
265                                                                                      \
266         for (int y = 0; y < height; y++) {                                           \
267             for (int x = 0; x < out->width; x++) {                                   \
268                 dst[x] = mix(xf0[x], xf1[x], progress);                              \
269             }                                                                        \
270                                                                                      \
271             dst += out->linesize[p] / div;                                           \
272             xf0 += a->linesize[p] / div;                                             \
273             xf1 += b->linesize[p] / div;                                             \
274         }                                                                            \
275     }                                                                                \
276 }
277
278 FADE_TRANSITION(8, uint8_t, 1)
279 FADE_TRANSITION(16, uint16_t, 2)
280
281 #define WIPELEFT_TRANSITION(name, type, div)                                         \
282 static void wipeleft##name##_transition(AVFilterContext *ctx,                        \
283                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
284                                 float progress,                                      \
285                                 int slice_start, int slice_end, int jobnr)           \
286 {                                                                                    \
287     XFadeContext *s = ctx->priv;                                                     \
288     const int height = slice_end - slice_start;                                      \
289     const int z = out->width * progress;                                             \
290                                                                                      \
291     for (int p = 0; p < s->nb_planes; p++) {                                         \
292         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
293         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
294         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
295                                                                                      \
296         for (int y = 0; y < height; y++) {                                           \
297             for (int x = 0; x < out->width; x++) {                                   \
298                 dst[x] = x > z ? xf1[x] : xf0[x];                                    \
299             }                                                                        \
300                                                                                      \
301             dst += out->linesize[p] / div;                                           \
302             xf0 += a->linesize[p] / div;                                             \
303             xf1 += b->linesize[p] / div;                                             \
304         }                                                                            \
305     }                                                                                \
306 }
307
308 WIPELEFT_TRANSITION(8, uint8_t, 1)
309 WIPELEFT_TRANSITION(16, uint16_t, 2)
310
311 #define WIPERIGHT_TRANSITION(name, type, div)                                        \
312 static void wiperight##name##_transition(AVFilterContext *ctx,                       \
313                                  const AVFrame *a, const AVFrame *b, AVFrame *out,   \
314                                  float progress,                                     \
315                                  int slice_start, int slice_end, int jobnr)          \
316 {                                                                                    \
317     XFadeContext *s = ctx->priv;                                                     \
318     const int height = slice_end - slice_start;                                      \
319     const int z = out->width * (1.f - progress);                                     \
320                                                                                      \
321     for (int p = 0; p < s->nb_planes; p++) {                                         \
322         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
323         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
324         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
325                                                                                      \
326         for (int y = 0; y < height; y++) {                                           \
327             for (int x = 0; x < out->width; x++) {                                   \
328                 dst[x] = x > z ? xf0[x] : xf1[x];                                    \
329             }                                                                        \
330                                                                                      \
331             dst += out->linesize[p] / div;                                           \
332             xf0 += a->linesize[p] / div;                                             \
333             xf1 += b->linesize[p] / div;                                             \
334         }                                                                            \
335     }                                                                                \
336 }
337
338 WIPERIGHT_TRANSITION(8, uint8_t, 1)
339 WIPERIGHT_TRANSITION(16, uint16_t, 2)
340
341 #define WIPEUP_TRANSITION(name, type, div)                                           \
342 static void wipeup##name##_transition(AVFilterContext *ctx,                          \
343                               const AVFrame *a, const AVFrame *b, AVFrame *out,      \
344                               float progress,                                        \
345                               int slice_start, int slice_end, int jobnr)             \
346 {                                                                                    \
347     XFadeContext *s = ctx->priv;                                                     \
348     const int height = slice_end - slice_start;                                      \
349     const int z = out->height * progress;                                            \
350                                                                                      \
351     for (int p = 0; p < s->nb_planes; p++) {                                         \
352         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
353         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
354         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
355                                                                                      \
356         for (int y = 0; y < height; y++) {                                           \
357             for (int x = 0; x < out->width; x++) {                                   \
358                 dst[x] = slice_start + y > z ? xf1[x] : xf0[x];                      \
359             }                                                                        \
360                                                                                      \
361             dst += out->linesize[p] / div;                                           \
362             xf0 += a->linesize[p] / div;                                             \
363             xf1 += b->linesize[p] / div;                                             \
364         }                                                                            \
365     }                                                                                \
366 }
367
368 WIPEUP_TRANSITION(8, uint8_t, 1)
369 WIPEUP_TRANSITION(16, uint16_t, 2)
370
371 #define WIPEDOWN_TRANSITION(name, type, div)                                         \
372 static void wipedown##name##_transition(AVFilterContext *ctx,                        \
373                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
374                                 float progress,                                      \
375                                 int slice_start, int slice_end, int jobnr)           \
376 {                                                                                    \
377     XFadeContext *s = ctx->priv;                                                     \
378     const int height = slice_end - slice_start;                                      \
379     const int z = out->height * (1.f - progress);                                    \
380                                                                                      \
381     for (int p = 0; p < s->nb_planes; p++) {                                         \
382         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
383         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
384         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
385                                                                                      \
386         for (int y = 0; y < height; y++) {                                           \
387             for (int x = 0; x < out->width; x++) {                                   \
388                 dst[x] = slice_start + y > z ? xf0[x] : xf1[x];                      \
389             }                                                                        \
390                                                                                      \
391             dst += out->linesize[p] / div;                                           \
392             xf0 += a->linesize[p] / div;                                             \
393             xf1 += b->linesize[p] / div;                                             \
394         }                                                                            \
395     }                                                                                \
396 }
397
398 WIPEDOWN_TRANSITION(8, uint8_t, 1)
399 WIPEDOWN_TRANSITION(16, uint16_t, 2)
400
401 #define SLIDELEFT_TRANSITION(name, type, div)                                        \
402 static void slideleft##name##_transition(AVFilterContext *ctx,                       \
403                                  const AVFrame *a, const AVFrame *b, AVFrame *out,   \
404                                  float progress,                                     \
405                                  int slice_start, int slice_end, int jobnr)          \
406 {                                                                                    \
407     XFadeContext *s = ctx->priv;                                                     \
408     const int height = slice_end - slice_start;                                      \
409     const int width = out->width;                                                    \
410     const int z = -progress * width;                                                 \
411                                                                                      \
412     for (int p = 0; p < s->nb_planes; p++) {                                         \
413         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
414         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
415         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
416                                                                                      \
417         for (int y = 0; y < height; y++) {                                           \
418             for (int x = 0; x < width; x++) {                                        \
419                 const int zx = z + x;                                                \
420                 const int zz = zx % width + width * (zx < 0);                        \
421                 dst[x] = (zx > 0) && (zx < width) ? xf1[zz] : xf0[zz];               \
422             }                                                                        \
423                                                                                      \
424             dst += out->linesize[p] / div;                                           \
425             xf0 += a->linesize[p] / div;                                             \
426             xf1 += b->linesize[p] / div;                                             \
427         }                                                                            \
428     }                                                                                \
429 }
430
431 SLIDELEFT_TRANSITION(8, uint8_t, 1)
432 SLIDELEFT_TRANSITION(16, uint16_t, 2)
433
434 #define SLIDERIGHT_TRANSITION(name, type, div)                                       \
435 static void slideright##name##_transition(AVFilterContext *ctx,                      \
436                                   const AVFrame *a, const AVFrame *b, AVFrame *out,  \
437                                   float progress,                                    \
438                                   int slice_start, int slice_end, int jobnr)         \
439 {                                                                                    \
440     XFadeContext *s = ctx->priv;                                                     \
441     const int height = slice_end - slice_start;                                      \
442     const int width = out->width;                                                    \
443     const int z = progress * width;                                                  \
444                                                                                      \
445     for (int p = 0; p < s->nb_planes; p++) {                                         \
446         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
447         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
448         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
449                                                                                      \
450         for (int y = 0; y < height; y++) {                                           \
451             for (int x = 0; x < out->width; x++) {                                   \
452                 const int zx = z + x;                                                \
453                 const int zz = zx % width + width * (zx < 0);                        \
454                 dst[x] = (zx > 0) && (zx < width) ? xf1[zz] : xf0[zz];               \
455             }                                                                        \
456                                                                                      \
457             dst += out->linesize[p] / div;                                           \
458             xf0 += a->linesize[p] / div;                                             \
459             xf1 += b->linesize[p] / div;                                             \
460         }                                                                            \
461     }                                                                                \
462 }
463
464 SLIDERIGHT_TRANSITION(8, uint8_t, 1)
465 SLIDERIGHT_TRANSITION(16, uint16_t, 2)
466
467 #define SLIDEUP_TRANSITION(name, type, div)                                         \
468 static void slideup##name##_transition(AVFilterContext *ctx,                        \
469                                const AVFrame *a, const AVFrame *b, AVFrame *out,    \
470                                float progress,                                      \
471                                int slice_start, int slice_end, int jobnr)           \
472 {                                                                                   \
473     XFadeContext *s = ctx->priv;                                                    \
474     const int height = out->height;                                                 \
475     const int z = -progress * height;                                               \
476                                                                                     \
477     for (int p = 0; p < s->nb_planes; p++) {                                        \
478         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);        \
479                                                                                     \
480         for (int y = slice_start; y < slice_end; y++) {                             \
481             const int zy = z + y;                                                   \
482             const int zz = zy % height + height * (zy < 0);                         \
483             const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]);     \
484             const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]);     \
485                                                                                     \
486             for (int x = 0; x < out->width; x++) {                                  \
487                 dst[x] = (zy > 0) && (zy < height) ? xf1[x] : xf0[x];               \
488             }                                                                       \
489                                                                                     \
490             dst += out->linesize[p] / div;                                          \
491         }                                                                           \
492     }                                                                               \
493 }
494
495 SLIDEUP_TRANSITION(8, uint8_t, 1)
496 SLIDEUP_TRANSITION(16, uint16_t, 2)
497
498 #define SLIDEDOWN_TRANSITION(name, type, div)                                       \
499 static void slidedown##name##_transition(AVFilterContext *ctx,                      \
500                                  const AVFrame *a, const AVFrame *b, AVFrame *out,  \
501                                  float progress,                                    \
502                                  int slice_start, int slice_end, int jobnr)         \
503 {                                                                                   \
504     XFadeContext *s = ctx->priv;                                                    \
505     const int height = out->height;                                                 \
506     const int z = progress * height;                                                \
507                                                                                     \
508     for (int p = 0; p < s->nb_planes; p++) {                                        \
509         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);        \
510                                                                                     \
511         for (int y = slice_start; y < slice_end; y++) {                             \
512             const int zy = z + y;                                                   \
513             const int zz = zy % height + height * (zy < 0);                         \
514             const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]);     \
515             const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]);     \
516                                                                                     \
517             for (int x = 0; x < out->width; x++) {                                  \
518                 dst[x] = (zy > 0) && (zy < height) ? xf1[x] : xf0[x];               \
519             }                                                                       \
520                                                                                     \
521             dst += out->linesize[p] / div;                                          \
522         }                                                                           \
523     }                                                                               \
524 }
525
526 SLIDEDOWN_TRANSITION(8, uint8_t, 1)
527 SLIDEDOWN_TRANSITION(16, uint16_t, 2)
528
529 #define CIRCLECROP_TRANSITION(name, type, div)                                      \
530 static void circlecrop##name##_transition(AVFilterContext *ctx,                     \
531                                  const AVFrame *a, const AVFrame *b, AVFrame *out,  \
532                                  float progress,                                    \
533                                  int slice_start, int slice_end, int jobnr)         \
534 {                                                                                   \
535     XFadeContext *s = ctx->priv;                                                    \
536     const int width = out->width;                                                   \
537     const int height = out->height;                                                 \
538     float z = powf(2.f * fabsf(progress - 0.5f), 3.f) * hypotf(width/2, height/2);  \
539                                                                                     \
540     for (int p = 0; p < s->nb_planes; p++) {                                        \
541         const int bg = s->black[p];                                                 \
542         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);        \
543                                                                                     \
544         for (int y = slice_start; y < slice_end; y++) {                             \
545             const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);      \
546             const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);      \
547                                                                                     \
548             for (int x = 0; x < width; x++) {                                       \
549                 float dist = hypotf(x - width / 2, y - height / 2);                 \
550                 int val = progress < 0.5f ? xf1[x] : xf0[x];                        \
551                 dst[x] = (z < dist) ? bg : val;                                     \
552             }                                                                       \
553                                                                                     \
554             dst += out->linesize[p] / div;                                          \
555         }                                                                           \
556     }                                                                               \
557 }
558
559 CIRCLECROP_TRANSITION(8, uint8_t, 1)
560 CIRCLECROP_TRANSITION(16, uint16_t, 2)
561
562 #define RECTCROP_TRANSITION(name, type, div)                                        \
563 static void rectcrop##name##_transition(AVFilterContext *ctx,                       \
564                                  const AVFrame *a, const AVFrame *b, AVFrame *out,  \
565                                  float progress,                                    \
566                                  int slice_start, int slice_end, int jobnr)         \
567 {                                                                                   \
568     XFadeContext *s = ctx->priv;                                                    \
569     const int width = out->width;                                                   \
570     const int height = out->height;                                                 \
571     int zh = fabsf(progress - 0.5f) * height;                                       \
572     int zw = fabsf(progress - 0.5f) * width;                                        \
573                                                                                     \
574     for (int p = 0; p < s->nb_planes; p++) {                                        \
575         const int bg = s->black[p];                                                 \
576         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);        \
577                                                                                     \
578         for (int y = slice_start; y < slice_end; y++) {                             \
579             const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);      \
580             const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);      \
581                                                                                     \
582             for (int x = 0; x < width; x++) {                                       \
583                 int dist = FFABS(x - width  / 2) < zw &&                            \
584                            FFABS(y - height / 2) < zh;                              \
585                 int val = progress < 0.5f ? xf1[x] : xf0[x];                        \
586                 dst[x] = !dist ? bg : val;                                          \
587             }                                                                       \
588                                                                                     \
589             dst += out->linesize[p] / div;                                          \
590         }                                                                           \
591     }                                                                               \
592 }
593
594 RECTCROP_TRANSITION(8, uint8_t, 1)
595 RECTCROP_TRANSITION(16, uint16_t, 2)
596
597 #define DISTANCE_TRANSITION(name, type, div)                                        \
598 static void distance##name##_transition(AVFilterContext *ctx,                       \
599                                  const AVFrame *a, const AVFrame *b, AVFrame *out,  \
600                                  float progress,                                    \
601                                  int slice_start, int slice_end, int jobnr)         \
602 {                                                                                   \
603     XFadeContext *s = ctx->priv;                                                    \
604     const int width = out->width;                                                   \
605     const float max = s->max_value;                                                 \
606                                                                                     \
607     for (int y = slice_start; y < slice_end; y++) {                                 \
608         for (int x = 0; x < width; x++) {                                           \
609             float dist = 0.f;                                                       \
610             for (int p = 0; p < s->nb_planes; p++) {                                \
611                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);  \
612                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);  \
613                                                                                     \
614                 dist += (xf0[x] / max - xf1[x] / max) *                             \
615                         (xf0[x] / max - xf1[x] / max);                              \
616             }                                                                       \
617                                                                                     \
618             dist = sqrtf(dist) <= progress;                                         \
619             for (int p = 0; p < s->nb_planes; p++) {                                \
620                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);  \
621                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);  \
622                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);          \
623                 dst[x] = mix(mix(xf0[x], xf1[x], dist), xf1[x], progress);          \
624             }                                                                       \
625         }                                                                           \
626     }                                                                               \
627 }
628
629 DISTANCE_TRANSITION(8, uint8_t, 1)
630 DISTANCE_TRANSITION(16, uint16_t, 2)
631
632 #define FADEBLACK_TRANSITION(name, type, div)                                        \
633 static void fadeblack##name##_transition(AVFilterContext *ctx,                       \
634                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
635                             float progress,                                          \
636                             int slice_start, int slice_end, int jobnr)               \
637 {                                                                                    \
638     XFadeContext *s = ctx->priv;                                                     \
639     const int height = slice_end - slice_start;                                      \
640     const float phase = 0.2f;                                                        \
641                                                                                      \
642     for (int p = 0; p < s->nb_planes; p++) {                                         \
643         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
644         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
645         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
646         const int bg = s->black[p];                                                  \
647                                                                                      \
648         for (int y = 0; y < height; y++) {                                           \
649             for (int x = 0; x < out->width; x++) {                                   \
650                 dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)),  \
651                          mix(bg, xf1[x], smoothstep(phase, 1.f, progress)),          \
652                              progress);                                              \
653             }                                                                        \
654                                                                                      \
655             dst += out->linesize[p] / div;                                           \
656             xf0 += a->linesize[p] / div;                                             \
657             xf1 += b->linesize[p] / div;                                             \
658         }                                                                            \
659     }                                                                                \
660 }
661
662 FADEBLACK_TRANSITION(8, uint8_t, 1)
663 FADEBLACK_TRANSITION(16, uint16_t, 2)
664
665 #define FADEWHITE_TRANSITION(name, type, div)                                        \
666 static void fadewhite##name##_transition(AVFilterContext *ctx,                       \
667                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
668                             float progress,                                          \
669                             int slice_start, int slice_end, int jobnr)               \
670 {                                                                                    \
671     XFadeContext *s = ctx->priv;                                                     \
672     const int height = slice_end - slice_start;                                      \
673     const float phase = 0.2f;                                                        \
674                                                                                      \
675     for (int p = 0; p < s->nb_planes; p++) {                                         \
676         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
677         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
678         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
679         const int bg = s->white[p];                                                  \
680                                                                                      \
681         for (int y = 0; y < height; y++) {                                           \
682             for (int x = 0; x < out->width; x++) {                                   \
683                 dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)),  \
684                          mix(bg, xf1[x], smoothstep(phase, 1.f, progress)),          \
685                              progress);                                              \
686             }                                                                        \
687                                                                                      \
688             dst += out->linesize[p] / div;                                           \
689             xf0 += a->linesize[p] / div;                                             \
690             xf1 += b->linesize[p] / div;                                             \
691         }                                                                            \
692     }                                                                                \
693 }
694
695 FADEWHITE_TRANSITION(8, uint8_t, 1)
696 FADEWHITE_TRANSITION(16, uint16_t, 2)
697
698 #define RADIAL_TRANSITION(name, type, div)                                           \
699 static void radial##name##_transition(AVFilterContext *ctx,                          \
700                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
701                             float progress,                                          \
702                             int slice_start, int slice_end, int jobnr)               \
703 {                                                                                    \
704     XFadeContext *s = ctx->priv;                                                     \
705     const int width = out->width;                                                    \
706     const int height = out->height;                                                  \
707                                                                                      \
708     for (int y = slice_start; y < slice_end; y++) {                                  \
709         for (int x = 0; x < width; x++) {                                            \
710             const float smooth = atan2f(x - width / 2, y - height / 2) -             \
711                                  (progress - 0.5f) * (M_PI * 2.5f);                  \
712             for (int p = 0; p < s->nb_planes; p++) {                                 \
713                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
714                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
715                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
716                                                                                      \
717                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
718             }                                                                        \
719         }                                                                            \
720     }                                                                                \
721 }
722
723 RADIAL_TRANSITION(8, uint8_t, 1)
724 RADIAL_TRANSITION(16, uint16_t, 2)
725
726 #define SMOOTHLEFT_TRANSITION(name, type, div)                                       \
727 static void smoothleft##name##_transition(AVFilterContext *ctx,                      \
728                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
729                             float progress,                                          \
730                             int slice_start, int slice_end, int jobnr)               \
731 {                                                                                    \
732     XFadeContext *s = ctx->priv;                                                     \
733     const int width = out->width;                                                    \
734     const float w = width;                                                           \
735                                                                                      \
736     for (int y = slice_start; y < slice_end; y++) {                                  \
737         for (int x = 0; x < width; x++) {                                            \
738             const float smooth = 1.f + x / w - progress * 2.f;                       \
739                                                                                      \
740             for (int p = 0; p < s->nb_planes; p++) {                                 \
741                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
742                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
743                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
744                                                                                      \
745                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
746             }                                                                        \
747         }                                                                            \
748     }                                                                                \
749 }
750
751 SMOOTHLEFT_TRANSITION(8, uint8_t, 1)
752 SMOOTHLEFT_TRANSITION(16, uint16_t, 2)
753
754 #define SMOOTHRIGHT_TRANSITION(name, type, div)                                      \
755 static void smoothright##name##_transition(AVFilterContext *ctx,                     \
756                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
757                             float progress,                                          \
758                             int slice_start, int slice_end, int jobnr)               \
759 {                                                                                    \
760     XFadeContext *s = ctx->priv;                                                     \
761     const int width = out->width;                                                    \
762     const float w = width;                                                           \
763                                                                                      \
764     for (int y = slice_start; y < slice_end; y++) {                                  \
765         for (int x = 0; x < width; x++) {                                            \
766             const float smooth = 1.f + (w - 1 - x) / w - progress * 2.f;             \
767                                                                                      \
768             for (int p = 0; p < s->nb_planes; p++) {                                 \
769                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
770                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
771                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
772                                                                                      \
773                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
774             }                                                                        \
775         }                                                                            \
776     }                                                                                \
777 }
778
779 SMOOTHRIGHT_TRANSITION(8, uint8_t, 1)
780 SMOOTHRIGHT_TRANSITION(16, uint16_t, 2)
781
782 #define SMOOTHUP_TRANSITION(name, type, div)                                         \
783 static void smoothup##name##_transition(AVFilterContext *ctx,                        \
784                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
785                             float progress,                                          \
786                             int slice_start, int slice_end, int jobnr)               \
787 {                                                                                    \
788     XFadeContext *s = ctx->priv;                                                     \
789     const int width = out->width;                                                    \
790     const float h = out->height;                                                     \
791                                                                                      \
792     for (int y = slice_start; y < slice_end; y++) {                                  \
793         const float smooth = 1.f + y / h - progress * 2.f;                           \
794         for (int x = 0; x < width; x++) {                                            \
795             for (int p = 0; p < s->nb_planes; p++) {                                 \
796                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
797                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
798                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
799                                                                                      \
800                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
801             }                                                                        \
802         }                                                                            \
803     }                                                                                \
804 }
805
806 SMOOTHUP_TRANSITION(8, uint8_t, 1)
807 SMOOTHUP_TRANSITION(16, uint16_t, 2)
808
809 #define SMOOTHDOWN_TRANSITION(name, type, div)                                       \
810 static void smoothdown##name##_transition(AVFilterContext *ctx,                      \
811                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
812                             float progress,                                          \
813                             int slice_start, int slice_end, int jobnr)               \
814 {                                                                                    \
815     XFadeContext *s = ctx->priv;                                                     \
816     const int width = out->width;                                                    \
817     const float h = out->height;                                                     \
818                                                                                      \
819     for (int y = slice_start; y < slice_end; y++) {                                  \
820         const float smooth = 1.f + (h - 1 - y) / h - progress * 2.f;                 \
821         for (int x = 0; x < width; x++) {                                            \
822             for (int p = 0; p < s->nb_planes; p++) {                                 \
823                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
824                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
825                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
826                                                                                      \
827                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
828             }                                                                        \
829         }                                                                            \
830     }                                                                                \
831 }
832
833 SMOOTHDOWN_TRANSITION(8, uint8_t, 1)
834 SMOOTHDOWN_TRANSITION(16, uint16_t, 2)
835
836 #define CIRCLEOPEN_TRANSITION(name, type, div)                                       \
837 static void circleopen##name##_transition(AVFilterContext *ctx,                      \
838                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
839                             float progress,                                          \
840                             int slice_start, int slice_end, int jobnr)               \
841 {                                                                                    \
842     XFadeContext *s = ctx->priv;                                                     \
843     const int width = out->width;                                                    \
844     const int height = out->height;                                                  \
845     const float z = hypotf(width / 2, height / 2);                                   \
846     const float p = (progress - 0.5f) * 3.f;                                         \
847                                                                                      \
848     for (int y = slice_start; y < slice_end; y++) {                                  \
849         for (int x = 0; x < width; x++) {                                            \
850             const float smooth = hypotf(x - width / 2, y - height / 2) / z + p;      \
851             for (int p = 0; p < s->nb_planes; p++) {                                 \
852                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
853                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
854                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
855                                                                                      \
856                 dst[x] = mix(xf0[x], xf1[x], smoothstep(0.f, 1.f, smooth));          \
857             }                                                                        \
858         }                                                                            \
859     }                                                                                \
860 }
861
862 CIRCLEOPEN_TRANSITION(8, uint8_t, 1)
863 CIRCLEOPEN_TRANSITION(16, uint16_t, 2)
864
865 #define CIRCLECLOSE_TRANSITION(name, type, div)                                      \
866 static void circleclose##name##_transition(AVFilterContext *ctx,                     \
867                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
868                             float progress,                                          \
869                             int slice_start, int slice_end, int jobnr)               \
870 {                                                                                    \
871     XFadeContext *s = ctx->priv;                                                     \
872     const int width = out->width;                                                    \
873     const int height = out->height;                                                  \
874     const float z = hypotf(width / 2, height / 2);                                   \
875     const float p = (1.f - progress - 0.5f) * 3.f;                                   \
876                                                                                      \
877     for (int y = slice_start; y < slice_end; y++) {                                  \
878         for (int x = 0; x < width; x++) {                                            \
879             const float smooth = hypotf(x - width / 2, y - height / 2) / z + p;      \
880             for (int p = 0; p < s->nb_planes; p++) {                                 \
881                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
882                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
883                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
884                                                                                      \
885                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
886             }                                                                        \
887         }                                                                            \
888     }                                                                                \
889 }
890
891 CIRCLECLOSE_TRANSITION(8, uint8_t, 1)
892 CIRCLECLOSE_TRANSITION(16, uint16_t, 2)
893
894 #define VERTOPEN_TRANSITION(name, type, div)                                         \
895 static void vertopen##name##_transition(AVFilterContext *ctx,                        \
896                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
897                             float progress,                                          \
898                             int slice_start, int slice_end, int jobnr)               \
899 {                                                                                    \
900     XFadeContext *s = ctx->priv;                                                     \
901     const int width = out->width;                                                    \
902     const float w2 = out->width / 2;                                                 \
903                                                                                      \
904     for (int y = slice_start; y < slice_end; y++) {                                  \
905         for (int x = 0; x < width; x++) {                                            \
906             const float smooth = 2.f - fabsf((x - w2) / w2) - progress * 2.f;        \
907             for (int p = 0; p < s->nb_planes; p++) {                                 \
908                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
909                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
910                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
911                                                                                      \
912                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
913             }                                                                        \
914         }                                                                            \
915     }                                                                                \
916 }
917
918 VERTOPEN_TRANSITION(8, uint8_t, 1)
919 VERTOPEN_TRANSITION(16, uint16_t, 2)
920
921 #define VERTCLOSE_TRANSITION(name, type, div)                                        \
922 static void vertclose##name##_transition(AVFilterContext *ctx,                       \
923                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
924                             float progress,                                          \
925                             int slice_start, int slice_end, int jobnr)               \
926 {                                                                                    \
927     XFadeContext *s = ctx->priv;                                                     \
928     const int width = out->width;                                                    \
929     const float w2 = out->width / 2;                                                 \
930                                                                                      \
931     for (int y = slice_start; y < slice_end; y++) {                                  \
932         for (int x = 0; x < width; x++) {                                            \
933             const float smooth = 1.f + fabsf((x - w2) / w2) - progress * 2.f;        \
934             for (int p = 0; p < s->nb_planes; p++) {                                 \
935                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
936                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
937                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
938                                                                                      \
939                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
940             }                                                                        \
941         }                                                                            \
942     }                                                                                \
943 }
944
945 VERTCLOSE_TRANSITION(8, uint8_t, 1)
946 VERTCLOSE_TRANSITION(16, uint16_t, 2)
947
948 #define HORZOPEN_TRANSITION(name, type, div)                                         \
949 static void horzopen##name##_transition(AVFilterContext *ctx,                        \
950                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
951                             float progress,                                          \
952                             int slice_start, int slice_end, int jobnr)               \
953 {                                                                                    \
954     XFadeContext *s = ctx->priv;                                                     \
955     const int width = out->width;                                                    \
956     const float h2 = out->height / 2;                                                \
957                                                                                      \
958     for (int y = slice_start; y < slice_end; y++) {                                  \
959         const float smooth = 2.f - fabsf((y - h2) / h2) - progress * 2.f;            \
960         for (int x = 0; x < width; x++) {                                            \
961             for (int p = 0; p < s->nb_planes; p++) {                                 \
962                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
963                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
964                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
965                                                                                      \
966                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
967             }                                                                        \
968         }                                                                            \
969     }                                                                                \
970 }
971
972 HORZOPEN_TRANSITION(8, uint8_t, 1)
973 HORZOPEN_TRANSITION(16, uint16_t, 2)
974
975 #define HORZCLOSE_TRANSITION(name, type, div)                                        \
976 static void horzclose##name##_transition(AVFilterContext *ctx,                       \
977                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
978                             float progress,                                          \
979                             int slice_start, int slice_end, int jobnr)               \
980 {                                                                                    \
981     XFadeContext *s = ctx->priv;                                                     \
982     const int width = out->width;                                                    \
983     const float h2 = out->height / 2;                                                \
984                                                                                      \
985     for (int y = slice_start; y < slice_end; y++) {                                  \
986         const float smooth = 1.f + fabsf((y - h2) / h2) - progress * 2.f;            \
987         for (int x = 0; x < width; x++) {                                            \
988             for (int p = 0; p < s->nb_planes; p++) {                                 \
989                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
990                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
991                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
992                                                                                      \
993                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
994             }                                                                        \
995         }                                                                            \
996     }                                                                                \
997 }
998
999 HORZCLOSE_TRANSITION(8, uint8_t, 1)
1000 HORZCLOSE_TRANSITION(16, uint16_t, 2)
1001
1002 static float frand(int x, int y)
1003 {
1004     const float r = sinf(x * 12.9898f + y * 78.233f) * 43758.545f;
1005
1006     return r - floorf(r);
1007 }
1008
1009 #define DISSOLVE_TRANSITION(name, type, div)                                         \
1010 static void dissolve##name##_transition(AVFilterContext *ctx,                        \
1011                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1012                             float progress,                                          \
1013                             int slice_start, int slice_end, int jobnr)               \
1014 {                                                                                    \
1015     XFadeContext *s = ctx->priv;                                                     \
1016     const int width = out->width;                                                    \
1017                                                                                      \
1018     for (int y = slice_start; y < slice_end; y++) {                                  \
1019         for (int x = 0; x < width; x++) {                                            \
1020             const float smooth = frand(x, y) * 2.f + progress * 2.f - 1.5f;          \
1021             for (int p = 0; p < s->nb_planes; p++) {                                 \
1022                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1023                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1024                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1025                                                                                      \
1026                 dst[x] = smooth >= 0.5f ? xf0[x] : xf1[x];                           \
1027             }                                                                        \
1028         }                                                                            \
1029     }                                                                                \
1030 }
1031
1032 DISSOLVE_TRANSITION(8, uint8_t, 1)
1033 DISSOLVE_TRANSITION(16, uint16_t, 2)
1034
1035 #define PIXELIZE_TRANSITION(name, type, div)                                         \
1036 static void pixelize##name##_transition(AVFilterContext *ctx,                        \
1037                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1038                             float progress,                                          \
1039                             int slice_start, int slice_end, int jobnr)               \
1040 {                                                                                    \
1041     XFadeContext *s = ctx->priv;                                                     \
1042     const int w = out->width;                                                        \
1043     const int h = out->height;                                                       \
1044     const float d = fminf(progress, 1.f - progress);                                 \
1045     const float dist = ceilf(d * 50.f) / 50.f;                                       \
1046     const float sqx = 2.f * dist * FFMIN(w, h) / 20.f;                               \
1047     const float sqy = 2.f * dist * FFMIN(w, h) / 20.f;                               \
1048                                                                                      \
1049     for (int y = slice_start; y < slice_end; y++) {                                  \
1050         for (int x = 0; x < w; x++) {                                                \
1051             int sx = dist > 0.f ? FFMIN((floorf(x / sqx) + .5f) * sqx, w - 1) : x;   \
1052             int sy = dist > 0.f ? FFMIN((floorf(y / sqy) + .5f) * sqy, h - 1) : y;   \
1053             for (int p = 0; p < s->nb_planes; p++) {                                 \
1054                 const type *xf0 = (const type *)(a->data[p] + sy * a->linesize[p]);  \
1055                 const type *xf1 = (const type *)(b->data[p] + sy * b->linesize[p]);  \
1056                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1057                                                                                      \
1058                 dst[x] = mix(xf0[sx], xf1[sx], progress);                            \
1059             }                                                                        \
1060         }                                                                            \
1061     }                                                                                \
1062 }
1063
1064 PIXELIZE_TRANSITION(8, uint8_t, 1)
1065 PIXELIZE_TRANSITION(16, uint16_t, 2)
1066
1067 #define DIAGTL_TRANSITION(name, type, div)                                           \
1068 static void diagtl##name##_transition(AVFilterContext *ctx,                          \
1069                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1070                             float progress,                                          \
1071                             int slice_start, int slice_end, int jobnr)               \
1072 {                                                                                    \
1073     XFadeContext *s = ctx->priv;                                                     \
1074     const int width = out->width;                                                    \
1075     const float w = width;                                                           \
1076     const float h = out->height;                                                     \
1077                                                                                      \
1078     for (int y = slice_start; y < slice_end; y++) {                                  \
1079         for (int x = 0; x < width; x++) {                                            \
1080             const float smooth = 1.f + x / w * y / h - progress * 2.f;               \
1081                                                                                      \
1082             for (int p = 0; p < s->nb_planes; p++) {                                 \
1083                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1084                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1085                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1086                                                                                      \
1087                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
1088             }                                                                        \
1089         }                                                                            \
1090     }                                                                                \
1091 }
1092
1093 DIAGTL_TRANSITION(8, uint8_t, 1)
1094 DIAGTL_TRANSITION(16, uint16_t, 2)
1095
1096 #define DIAGTR_TRANSITION(name, type, div)                                           \
1097 static void diagtr##name##_transition(AVFilterContext *ctx,                          \
1098                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1099                             float progress,                                          \
1100                             int slice_start, int slice_end, int jobnr)               \
1101 {                                                                                    \
1102     XFadeContext *s = ctx->priv;                                                     \
1103     const int width = out->width;                                                    \
1104     const float w = width;                                                           \
1105     const float h = out->height;                                                     \
1106                                                                                      \
1107     for (int y = slice_start; y < slice_end; y++) {                                  \
1108         for (int x = 0; x < width; x++) {                                            \
1109             const float smooth = 1.f + (w - 1 - x) / w * y / h - progress * 2.f;     \
1110                                                                                      \
1111             for (int p = 0; p < s->nb_planes; p++) {                                 \
1112                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1113                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1114                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1115                                                                                      \
1116                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
1117             }                                                                        \
1118         }                                                                            \
1119     }                                                                                \
1120 }
1121
1122 DIAGTR_TRANSITION(8, uint8_t, 1)
1123 DIAGTR_TRANSITION(16, uint16_t, 2)
1124
1125 #define DIAGBL_TRANSITION(name, type, div)                                           \
1126 static void diagbl##name##_transition(AVFilterContext *ctx,                          \
1127                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1128                             float progress,                                          \
1129                             int slice_start, int slice_end, int jobnr)               \
1130 {                                                                                    \
1131     XFadeContext *s = ctx->priv;                                                     \
1132     const int width = out->width;                                                    \
1133     const float w = width;                                                           \
1134     const float h = out->height;                                                     \
1135                                                                                      \
1136     for (int y = slice_start; y < slice_end; y++) {                                  \
1137         for (int x = 0; x < width; x++) {                                            \
1138             const float smooth = 1.f + x / w * (h - 1 - y) / h - progress * 2.f;     \
1139                                                                                      \
1140             for (int p = 0; p < s->nb_planes; p++) {                                 \
1141                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1142                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1143                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1144                                                                                      \
1145                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
1146             }                                                                        \
1147         }                                                                            \
1148     }                                                                                \
1149 }
1150
1151 DIAGBL_TRANSITION(8, uint8_t, 1)
1152 DIAGBL_TRANSITION(16, uint16_t, 2)
1153
1154 #define DIAGBR_TRANSITION(name, type, div)                                           \
1155 static void diagbr##name##_transition(AVFilterContext *ctx,                          \
1156                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1157                             float progress,                                          \
1158                             int slice_start, int slice_end, int jobnr)               \
1159 {                                                                                    \
1160     XFadeContext *s = ctx->priv;                                                     \
1161     const int width = out->width;                                                    \
1162     const float w = width;                                                           \
1163     const float h = out->height;                                                     \
1164                                                                                      \
1165     for (int y = slice_start; y < slice_end; y++) {                                  \
1166         for (int x = 0; x < width; x++) {                                            \
1167             const float smooth = 1.f + (w - 1 - x) / w * (h - 1 - y) / h -           \
1168                                  progress * 2.f;                                     \
1169                                                                                      \
1170             for (int p = 0; p < s->nb_planes; p++) {                                 \
1171                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1172                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1173                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1174                                                                                      \
1175                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
1176             }                                                                        \
1177         }                                                                            \
1178     }                                                                                \
1179 }
1180
1181 DIAGBR_TRANSITION(8, uint8_t, 1)
1182 DIAGBR_TRANSITION(16, uint16_t, 2)
1183
1184 #define HLSLICE_TRANSITION(name, type, div)                                          \
1185 static void hlslice##name##_transition(AVFilterContext *ctx,                         \
1186                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1187                             float progress,                                          \
1188                             int slice_start, int slice_end, int jobnr)               \
1189 {                                                                                    \
1190     XFadeContext *s = ctx->priv;                                                     \
1191     const int width = out->width;                                                    \
1192     const float w = width;                                                           \
1193                                                                                      \
1194     for (int y = slice_start; y < slice_end; y++) {                                  \
1195         for (int x = 0; x < width; x++) {                                            \
1196             const float smooth = smoothstep(-0.5f, 0.f, x / w - progress * 1.5f);    \
1197             const float ss = smooth <= fract(10.f * x / w) ? 0.f : 1.f;              \
1198                                                                                      \
1199             for (int p = 0; p < s->nb_planes; p++) {                                 \
1200                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1201                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1202                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1203                                                                                      \
1204                 dst[x] = mix(xf1[x], xf0[x], ss);                                    \
1205             }                                                                        \
1206         }                                                                            \
1207     }                                                                                \
1208 }
1209
1210 HLSLICE_TRANSITION(8, uint8_t, 1)
1211 HLSLICE_TRANSITION(16, uint16_t, 2)
1212
1213 #define HRSLICE_TRANSITION(name, type, div)                                          \
1214 static void hrslice##name##_transition(AVFilterContext *ctx,                         \
1215                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1216                             float progress,                                          \
1217                             int slice_start, int slice_end, int jobnr)               \
1218 {                                                                                    \
1219     XFadeContext *s = ctx->priv;                                                     \
1220     const int width = out->width;                                                    \
1221     const float w = width;                                                           \
1222                                                                                      \
1223     for (int y = slice_start; y < slice_end; y++) {                                  \
1224         for (int x = 0; x < width; x++) {                                            \
1225             const float xx = (w - 1 - x) / w;                                        \
1226             const float smooth = smoothstep(-0.5f, 0.f, xx - progress * 1.5f);       \
1227             const float ss = smooth <= fract(10.f * xx) ? 0.f : 1.f;                 \
1228                                                                                      \
1229             for (int p = 0; p < s->nb_planes; p++) {                                 \
1230                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1231                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1232                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1233                                                                                      \
1234                 dst[x] = mix(xf1[x], xf0[x], ss);                                    \
1235             }                                                                        \
1236         }                                                                            \
1237     }                                                                                \
1238 }
1239
1240 HRSLICE_TRANSITION(8, uint8_t, 1)
1241 HRSLICE_TRANSITION(16, uint16_t, 2)
1242
1243 #define VUSLICE_TRANSITION(name, type, div)                                          \
1244 static void vuslice##name##_transition(AVFilterContext *ctx,                         \
1245                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1246                             float progress,                                          \
1247                             int slice_start, int slice_end, int jobnr)               \
1248 {                                                                                    \
1249     XFadeContext *s = ctx->priv;                                                     \
1250     const int width = out->width;                                                    \
1251     const float h = out->height;                                                     \
1252                                                                                      \
1253     for (int y = slice_start; y < slice_end; y++) {                                  \
1254          const float smooth = smoothstep(-0.5f, 0.f, y / h - progress * 1.5f);       \
1255          const float ss = smooth <= fract(10.f * y / h) ? 0.f : 1.f;                 \
1256                                                                                      \
1257          for (int x = 0; x < width; x++) {                                           \
1258             for (int p = 0; p < s->nb_planes; p++) {                                 \
1259                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1260                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1261                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1262                                                                                      \
1263                 dst[x] = mix(xf1[x], xf0[x], ss);                                    \
1264             }                                                                        \
1265         }                                                                            \
1266     }                                                                                \
1267 }
1268
1269 VUSLICE_TRANSITION(8, uint8_t, 1)
1270 VUSLICE_TRANSITION(16, uint16_t, 2)
1271
1272 #define VDSLICE_TRANSITION(name, type, div)                                          \
1273 static void vdslice##name##_transition(AVFilterContext *ctx,                         \
1274                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1275                             float progress,                                          \
1276                             int slice_start, int slice_end, int jobnr)               \
1277 {                                                                                    \
1278     XFadeContext *s = ctx->priv;                                                     \
1279     const int width = out->width;                                                    \
1280     const float h = out->height;                                                     \
1281                                                                                      \
1282     for (int y = slice_start; y < slice_end; y++) {                                  \
1283          const float yy = (h - 1 - y) / h;                                           \
1284          const float smooth = smoothstep(-0.5f, 0.f, yy - progress * 1.5f);          \
1285          const float ss = smooth <= fract(10.f * yy) ? 0.f : 1.f;                    \
1286                                                                                      \
1287          for (int x = 0; x < width; x++) {                                           \
1288             for (int p = 0; p < s->nb_planes; p++) {                                 \
1289                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1290                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1291                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1292                                                                                      \
1293                 dst[x] = mix(xf1[x], xf0[x], ss);                                    \
1294             }                                                                        \
1295         }                                                                            \
1296     }                                                                                \
1297 }
1298
1299 VDSLICE_TRANSITION(8, uint8_t, 1)
1300 VDSLICE_TRANSITION(16, uint16_t, 2)
1301
1302 static inline double getpix(void *priv, double x, double y, int plane, int nb)
1303 {
1304     XFadeContext *s = priv;
1305     AVFrame *in = s->xf[nb];
1306     const uint8_t *src = in->data[FFMIN(plane, s->nb_planes - 1)];
1307     int linesize = in->linesize[FFMIN(plane, s->nb_planes - 1)];
1308     const int w = in->width;
1309     const int h = in->height;
1310
1311     int xi, yi;
1312
1313     xi = av_clipd(x, 0, w - 1);
1314     yi = av_clipd(y, 0, h - 1);
1315
1316     if (s->depth > 8) {
1317         const uint16_t *src16 = (const uint16_t*)src;
1318
1319         linesize /= 2;
1320         return src16[xi + yi * linesize];
1321     } else {
1322         return src[xi + yi * linesize];
1323     }
1324 }
1325
1326 static double a0(void *priv, double x, double y) { return getpix(priv, x, y, 0, 0); }
1327 static double a1(void *priv, double x, double y) { return getpix(priv, x, y, 1, 0); }
1328 static double a2(void *priv, double x, double y) { return getpix(priv, x, y, 2, 0); }
1329 static double a3(void *priv, double x, double y) { return getpix(priv, x, y, 3, 0); }
1330
1331 static double b0(void *priv, double x, double y) { return getpix(priv, x, y, 0, 1); }
1332 static double b1(void *priv, double x, double y) { return getpix(priv, x, y, 1, 1); }
1333 static double b2(void *priv, double x, double y) { return getpix(priv, x, y, 2, 1); }
1334 static double b3(void *priv, double x, double y) { return getpix(priv, x, y, 3, 1); }
1335
1336 static int config_output(AVFilterLink *outlink)
1337 {
1338     AVFilterContext *ctx = outlink->src;
1339     AVFilterLink *inlink0 = ctx->inputs[0];
1340     AVFilterLink *inlink1 = ctx->inputs[1];
1341     XFadeContext *s = ctx->priv;
1342     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink0->format);
1343     int is_rgb;
1344
1345     if (inlink0->format != inlink1->format) {
1346         av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n");
1347         return AVERROR(EINVAL);
1348     }
1349     if (inlink0->w != inlink1->w || inlink0->h != inlink1->h) {
1350         av_log(ctx, AV_LOG_ERROR, "First input link %s parameters "
1351                "(size %dx%d) do not match the corresponding "
1352                "second input link %s parameters (size %dx%d)\n",
1353                ctx->input_pads[0].name, inlink0->w, inlink0->h,
1354                ctx->input_pads[1].name, inlink1->w, inlink1->h);
1355         return AVERROR(EINVAL);
1356     }
1357
1358     if (inlink0->time_base.num != inlink1->time_base.num ||
1359         inlink0->time_base.den != inlink1->time_base.den) {
1360         av_log(ctx, AV_LOG_ERROR, "First input link %s timebase "
1361                "(%d/%d) do not match the corresponding "
1362                "second input link %s timebase (%d/%d)\n",
1363                ctx->input_pads[0].name, inlink0->time_base.num, inlink0->time_base.den,
1364                ctx->input_pads[1].name, inlink1->time_base.num, inlink1->time_base.den);
1365         return AVERROR(EINVAL);
1366     }
1367
1368     outlink->w = inlink0->w;
1369     outlink->h = inlink0->h;
1370     outlink->time_base = inlink0->time_base;
1371     outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
1372     outlink->frame_rate = inlink0->frame_rate;
1373
1374     s->depth = pix_desc->comp[0].depth;
1375     is_rgb = !!(pix_desc->flags & AV_PIX_FMT_FLAG_RGB);
1376     s->nb_planes = av_pix_fmt_count_planes(inlink0->format);
1377     s->max_value = (1 << s->depth) - 1;
1378     s->black[0] = 0;
1379     s->black[1] = s->black[2] = is_rgb ? 0 : s->max_value / 2;
1380     s->black[3] = s->max_value;
1381     s->white[0] = s->white[3] = s->max_value;
1382     s->white[1] = s->white[2] = is_rgb ? s->max_value : s->max_value / 2;
1383
1384     s->first_pts = s->last_pts = s->pts = AV_NOPTS_VALUE;
1385
1386     if (s->duration)
1387         s->duration_pts = av_rescale_q(s->duration, AV_TIME_BASE_Q, outlink->time_base);
1388     if (s->offset)
1389         s->offset_pts = av_rescale_q(s->offset, AV_TIME_BASE_Q, outlink->time_base);
1390
1391     switch (s->transition) {
1392     case CUSTOM:     s->transitionf = s->depth <= 8 ? custom8_transition     : custom16_transition;     break;
1393     case FADE:       s->transitionf = s->depth <= 8 ? fade8_transition       : fade16_transition;       break;
1394     case WIPELEFT:   s->transitionf = s->depth <= 8 ? wipeleft8_transition   : wipeleft16_transition;   break;
1395     case WIPERIGHT:  s->transitionf = s->depth <= 8 ? wiperight8_transition  : wiperight16_transition;  break;
1396     case WIPEUP:     s->transitionf = s->depth <= 8 ? wipeup8_transition     : wipeup16_transition;     break;
1397     case WIPEDOWN:   s->transitionf = s->depth <= 8 ? wipedown8_transition   : wipedown16_transition;   break;
1398     case SLIDELEFT:  s->transitionf = s->depth <= 8 ? slideleft8_transition  : slideleft16_transition;  break;
1399     case SLIDERIGHT: s->transitionf = s->depth <= 8 ? slideright8_transition : slideright16_transition; break;
1400     case SLIDEUP:    s->transitionf = s->depth <= 8 ? slideup8_transition    : slideup16_transition;    break;
1401     case SLIDEDOWN:  s->transitionf = s->depth <= 8 ? slidedown8_transition  : slidedown16_transition;  break;
1402     case CIRCLECROP: s->transitionf = s->depth <= 8 ? circlecrop8_transition : circlecrop16_transition; break;
1403     case RECTCROP:   s->transitionf = s->depth <= 8 ? rectcrop8_transition   : rectcrop16_transition;   break;
1404     case DISTANCE:   s->transitionf = s->depth <= 8 ? distance8_transition   : distance16_transition;   break;
1405     case FADEBLACK:  s->transitionf = s->depth <= 8 ? fadeblack8_transition  : fadeblack16_transition;  break;
1406     case FADEWHITE:  s->transitionf = s->depth <= 8 ? fadewhite8_transition  : fadewhite16_transition;  break;
1407     case RADIAL:     s->transitionf = s->depth <= 8 ? radial8_transition     : radial16_transition;     break;
1408     case SMOOTHLEFT: s->transitionf = s->depth <= 8 ? smoothleft8_transition : smoothleft16_transition; break;
1409     case SMOOTHRIGHT:s->transitionf = s->depth <= 8 ? smoothright8_transition: smoothright16_transition;break;
1410     case SMOOTHUP:   s->transitionf = s->depth <= 8 ? smoothup8_transition   : smoothup16_transition;   break;
1411     case SMOOTHDOWN: s->transitionf = s->depth <= 8 ? smoothdown8_transition : smoothdown16_transition; break;
1412     case CIRCLEOPEN: s->transitionf = s->depth <= 8 ? circleopen8_transition : circleopen16_transition; break;
1413     case CIRCLECLOSE:s->transitionf = s->depth <= 8 ? circleclose8_transition: circleclose16_transition;break;
1414     case VERTOPEN:   s->transitionf = s->depth <= 8 ? vertopen8_transition   : vertopen16_transition;   break;
1415     case VERTCLOSE:  s->transitionf = s->depth <= 8 ? vertclose8_transition  : vertclose16_transition;  break;
1416     case HORZOPEN:   s->transitionf = s->depth <= 8 ? horzopen8_transition   : horzopen16_transition;   break;
1417     case HORZCLOSE:  s->transitionf = s->depth <= 8 ? horzclose8_transition  : horzclose16_transition;  break;
1418     case DISSOLVE:   s->transitionf = s->depth <= 8 ? dissolve8_transition   : dissolve16_transition;   break;
1419     case PIXELIZE:   s->transitionf = s->depth <= 8 ? pixelize8_transition   : pixelize16_transition;   break;
1420     case DIAGTL:     s->transitionf = s->depth <= 8 ? diagtl8_transition     : diagtl16_transition;     break;
1421     case DIAGTR:     s->transitionf = s->depth <= 8 ? diagtr8_transition     : diagtr16_transition;     break;
1422     case DIAGBL:     s->transitionf = s->depth <= 8 ? diagbl8_transition     : diagbl16_transition;     break;
1423     case DIAGBR:     s->transitionf = s->depth <= 8 ? diagbr8_transition     : diagbr16_transition;     break;
1424     case HLSLICE:    s->transitionf = s->depth <= 8 ? hlslice8_transition    : hlslice16_transition;    break;
1425     case HRSLICE:    s->transitionf = s->depth <= 8 ? hrslice8_transition    : hrslice16_transition;    break;
1426     case VUSLICE:    s->transitionf = s->depth <= 8 ? vuslice8_transition    : vuslice16_transition;    break;
1427     case VDSLICE:    s->transitionf = s->depth <= 8 ? vdslice8_transition    : vdslice16_transition;    break;
1428     }
1429
1430     if (s->transition == CUSTOM) {
1431         static const char *const func2_names[]    = {
1432             "a0", "a1", "a2", "a3",
1433             "b0", "b1", "b2", "b3",
1434             NULL
1435         };
1436         double (*func2[])(void *, double, double) = {
1437             a0, a1, a2, a3,
1438             b0, b1, b2, b3,
1439             NULL };
1440         int ret;
1441
1442         if (!s->custom_str)
1443             return AVERROR(EINVAL);
1444         ret = av_expr_parse(&s->e, s->custom_str, var_names,
1445                             NULL, NULL, func2_names, func2, 0, ctx);
1446         if (ret < 0)
1447             return ret;
1448     }
1449
1450     return 0;
1451 }
1452
1453 static int xfade_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
1454 {
1455     XFadeContext *s = ctx->priv;
1456     AVFilterLink *outlink = ctx->outputs[0];
1457     ThreadData *td = arg;
1458     int slice_start = (outlink->h *  jobnr   ) / nb_jobs;
1459     int slice_end   = (outlink->h * (jobnr+1)) / nb_jobs;
1460
1461     s->transitionf(ctx, td->xf[0], td->xf[1], td->out, td->progress, slice_start, slice_end, jobnr);
1462
1463     return 0;
1464 }
1465
1466 static int xfade_frame(AVFilterContext *ctx, AVFrame *a, AVFrame *b)
1467 {
1468     XFadeContext *s = ctx->priv;
1469     AVFilterLink *outlink = ctx->outputs[0];
1470     float progress = av_clipf(1.f - ((float)(s->pts - s->first_pts - s->offset_pts) / s->duration_pts), 0.f, 1.f);
1471     ThreadData td;
1472     AVFrame *out;
1473
1474     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1475     if (!out)
1476         return AVERROR(ENOMEM);
1477
1478     td.xf[0] = a, td.xf[1] = b, td.out = out, td.progress = progress;
1479     ctx->internal->execute(ctx, xfade_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
1480
1481     out->pts = s->pts;
1482
1483     return ff_filter_frame(outlink, out);
1484 }
1485
1486 static int xfade_activate(AVFilterContext *ctx)
1487 {
1488     XFadeContext *s = ctx->priv;
1489     AVFilterLink *outlink = ctx->outputs[0];
1490     AVFrame *in = NULL;
1491     int ret = 0, status;
1492     int64_t pts;
1493
1494     FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
1495
1496     if (s->xfade_is_over) {
1497         ret = ff_inlink_consume_frame(ctx->inputs[1], &in);
1498         if (ret < 0) {
1499             return ret;
1500         } else if (ret > 0) {
1501             in->pts = (in->pts - s->last_pts) + s->pts;
1502             return ff_filter_frame(outlink, in);
1503         } else if (ff_inlink_acknowledge_status(ctx->inputs[1], &status, &pts)) {
1504             ff_outlink_set_status(outlink, status, s->pts);
1505             return 0;
1506         } else if (!ret) {
1507             if (ff_outlink_frame_wanted(outlink)) {
1508                 ff_inlink_request_frame(ctx->inputs[1]);
1509                 return 0;
1510             }
1511         }
1512     }
1513
1514     if (ff_inlink_queued_frames(ctx->inputs[0]) > 0) {
1515         s->xf[0] = ff_inlink_peek_frame(ctx->inputs[0], 0);
1516         if (s->xf[0]) {
1517             if (s->first_pts == AV_NOPTS_VALUE) {
1518                 s->first_pts = s->xf[0]->pts;
1519             }
1520             s->pts = s->xf[0]->pts;
1521             if (s->first_pts + s->offset_pts > s->xf[0]->pts) {
1522                 s->xf[0] = NULL;
1523                 s->need_second = 0;
1524                 ff_inlink_consume_frame(ctx->inputs[0], &in);
1525                 return ff_filter_frame(outlink, in);
1526             }
1527
1528             s->need_second = 1;
1529         }
1530     }
1531
1532     if (s->xf[0] && ff_inlink_queued_frames(ctx->inputs[1]) > 0) {
1533         ff_inlink_consume_frame(ctx->inputs[0], &s->xf[0]);
1534         ff_inlink_consume_frame(ctx->inputs[1], &s->xf[1]);
1535
1536         s->last_pts = s->xf[1]->pts;
1537         s->pts = s->xf[0]->pts;
1538         if (s->xf[0]->pts - (s->first_pts + s->offset_pts) > s->duration_pts)
1539             s->xfade_is_over = 1;
1540         ret = xfade_frame(ctx, s->xf[0], s->xf[1]);
1541         av_frame_free(&s->xf[0]);
1542         av_frame_free(&s->xf[1]);
1543         return ret;
1544     }
1545
1546     if (ff_inlink_queued_frames(ctx->inputs[0]) > 0 &&
1547         ff_inlink_queued_frames(ctx->inputs[1]) > 0) {
1548         ff_filter_set_ready(ctx, 100);
1549         return 0;
1550     }
1551
1552     if (ff_outlink_frame_wanted(outlink)) {
1553         if (!s->eof[0] && ff_outlink_get_status(ctx->inputs[0])) {
1554             s->eof[0] = 1;
1555             s->xfade_is_over = 1;
1556         }
1557         if (!s->eof[1] && ff_outlink_get_status(ctx->inputs[1])) {
1558             s->eof[1] = 1;
1559         }
1560         if (!s->eof[0] && !s->xf[0])
1561             ff_inlink_request_frame(ctx->inputs[0]);
1562         if (!s->eof[1] && (s->need_second || s->eof[0]))
1563             ff_inlink_request_frame(ctx->inputs[1]);
1564         if (s->eof[0] && s->eof[1] && (
1565             ff_inlink_queued_frames(ctx->inputs[0]) <= 0 ||
1566             ff_inlink_queued_frames(ctx->inputs[1]) <= 0))
1567             ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE);
1568         return 0;
1569     }
1570
1571     return FFERROR_NOT_READY;
1572 }
1573
1574 static const AVFilterPad xfade_inputs[] = {
1575     {
1576         .name          = "main",
1577         .type          = AVMEDIA_TYPE_VIDEO,
1578     },
1579     {
1580         .name          = "xfade",
1581         .type          = AVMEDIA_TYPE_VIDEO,
1582     },
1583     { NULL }
1584 };
1585
1586 static const AVFilterPad xfade_outputs[] = {
1587     {
1588         .name          = "default",
1589         .type          = AVMEDIA_TYPE_VIDEO,
1590         .config_props  = config_output,
1591     },
1592     { NULL }
1593 };
1594
1595 AVFilter ff_vf_xfade = {
1596     .name          = "xfade",
1597     .description   = NULL_IF_CONFIG_SMALL("Cross fade one video with another video."),
1598     .priv_size     = sizeof(XFadeContext),
1599     .priv_class    = &xfade_class,
1600     .query_formats = query_formats,
1601     .activate      = xfade_activate,
1602     .uninit        = uninit,
1603     .inputs        = xfade_inputs,
1604     .outputs       = xfade_outputs,
1605     .flags         = AVFILTER_FLAG_SLICE_THREADS,
1606 };