• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     HBLUR,
69     FADEGRAYS,
70     WIPETL,
71     WIPETR,
72     WIPEBL,
73     WIPEBR,
74     SQUEEZEH,
75     SQUEEZEV,
76     ZOOMIN,
77     FADEFAST,
78     FADESLOW,
79     NB_TRANSITIONS,
80 };
81 
82 typedef struct XFadeContext {
83     const AVClass *class;
84 
85     int     transition;
86     int64_t duration;
87     int64_t offset;
88     char   *custom_str;
89 
90     int nb_planes;
91     int depth;
92     int is_rgb;
93 
94     int64_t duration_pts;
95     int64_t offset_pts;
96     int64_t first_pts;
97     int64_t last_pts;
98     int64_t pts;
99     int xfade_is_over;
100     int need_second;
101     int eof[2];
102     AVFrame *xf[2];
103     int max_value;
104     uint16_t black[4];
105     uint16_t white[4];
106 
107     void (*transitionf)(AVFilterContext *ctx, const AVFrame *a, const AVFrame *b, AVFrame *out, float progress,
108                         int slice_start, int slice_end, int jobnr);
109 
110     AVExpr *e;
111 } XFadeContext;
112 
113 static const char *const var_names[] = {   "X",   "Y",   "W",   "H",   "A",   "B",   "PLANE",          "P",        NULL };
114 enum                                   { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_A, VAR_B, VAR_PLANE, VAR_PROGRESS, VAR_VARS_NB };
115 
116 typedef struct ThreadData {
117     const AVFrame *xf[2];
118     AVFrame *out;
119     float progress;
120 } ThreadData;
121 
122 static const enum AVPixelFormat pix_fmts[] = {
123     AV_PIX_FMT_YUVA444P,
124     AV_PIX_FMT_YUVJ444P,
125     AV_PIX_FMT_YUV444P,
126     AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8,
127     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_GBRP9,
128     AV_PIX_FMT_YUV444P10,
129     AV_PIX_FMT_YUVA444P10,
130     AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GRAY10,
131     AV_PIX_FMT_YUV444P12,
132     AV_PIX_FMT_YUVA444P12,
133     AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GRAY12,
134     AV_PIX_FMT_YUV444P14, AV_PIX_FMT_GBRP14,
135     AV_PIX_FMT_YUV444P16,
136     AV_PIX_FMT_YUVA444P16,
137     AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_GRAY16,
138     AV_PIX_FMT_NONE
139 };
140 
uninit(AVFilterContext * ctx)141 static av_cold void uninit(AVFilterContext *ctx)
142 {
143     XFadeContext *s = ctx->priv;
144 
145     av_expr_free(s->e);
146 }
147 
148 #define OFFSET(x) offsetof(XFadeContext, x)
149 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
150 
151 static const AVOption xfade_options[] = {
152     { "transition", "set cross fade transition", OFFSET(transition), AV_OPT_TYPE_INT, {.i64=FADE}, -1, NB_TRANSITIONS-1, FLAGS, "transition" },
153     {   "custom",    "custom transition",     0, AV_OPT_TYPE_CONST, {.i64=CUSTOM},    0, 0, FLAGS, "transition" },
154     {   "fade",      "fade transition",       0, AV_OPT_TYPE_CONST, {.i64=FADE},      0, 0, FLAGS, "transition" },
155     {   "wipeleft",  "wipe left transition",  0, AV_OPT_TYPE_CONST, {.i64=WIPELEFT},  0, 0, FLAGS, "transition" },
156     {   "wiperight", "wipe right transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPERIGHT}, 0, 0, FLAGS, "transition" },
157     {   "wipeup",    "wipe up transition",    0, AV_OPT_TYPE_CONST, {.i64=WIPEUP},    0, 0, FLAGS, "transition" },
158     {   "wipedown",  "wipe down transition",  0, AV_OPT_TYPE_CONST, {.i64=WIPEDOWN},  0, 0, FLAGS, "transition" },
159     {   "slideleft",  "slide left transition",  0, AV_OPT_TYPE_CONST, {.i64=SLIDELEFT},  0, 0, FLAGS, "transition" },
160     {   "slideright", "slide right transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDERIGHT}, 0, 0, FLAGS, "transition" },
161     {   "slideup",    "slide up transition",    0, AV_OPT_TYPE_CONST, {.i64=SLIDEUP},    0, 0, FLAGS, "transition" },
162     {   "slidedown",  "slide down transition",  0, AV_OPT_TYPE_CONST, {.i64=SLIDEDOWN},  0, 0, FLAGS, "transition" },
163     {   "circlecrop", "circle crop transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLECROP}, 0, 0, FLAGS, "transition" },
164     {   "rectcrop",   "rect crop transition",   0, AV_OPT_TYPE_CONST, {.i64=RECTCROP},   0, 0, FLAGS, "transition" },
165     {   "distance",   "distance transition",    0, AV_OPT_TYPE_CONST, {.i64=DISTANCE},   0, 0, FLAGS, "transition" },
166     {   "fadeblack",  "fadeblack transition",   0, AV_OPT_TYPE_CONST, {.i64=FADEBLACK},  0, 0, FLAGS, "transition" },
167     {   "fadewhite",  "fadewhite transition",   0, AV_OPT_TYPE_CONST, {.i64=FADEWHITE},  0, 0, FLAGS, "transition" },
168     {   "radial",     "radial transition",      0, AV_OPT_TYPE_CONST, {.i64=RADIAL},     0, 0, FLAGS, "transition" },
169     {   "smoothleft", "smoothleft transition",  0, AV_OPT_TYPE_CONST, {.i64=SMOOTHLEFT}, 0, 0, FLAGS, "transition" },
170     {   "smoothright","smoothright transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHRIGHT},0, 0, FLAGS, "transition" },
171     {   "smoothup",   "smoothup transition",    0, AV_OPT_TYPE_CONST, {.i64=SMOOTHUP},   0, 0, FLAGS, "transition" },
172     {   "smoothdown", "smoothdown transition",  0, AV_OPT_TYPE_CONST, {.i64=SMOOTHDOWN}, 0, 0, FLAGS, "transition" },
173     {   "circleopen", "circleopen transition",  0, AV_OPT_TYPE_CONST, {.i64=CIRCLEOPEN}, 0, 0, FLAGS, "transition" },
174     {   "circleclose","circleclose transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLECLOSE},0, 0, FLAGS, "transition" },
175     {   "vertopen",   "vert open transition",   0, AV_OPT_TYPE_CONST, {.i64=VERTOPEN},   0, 0, FLAGS, "transition" },
176     {   "vertclose",  "vert close transition",  0, AV_OPT_TYPE_CONST, {.i64=VERTCLOSE},  0, 0, FLAGS, "transition" },
177     {   "horzopen",   "horz open transition",   0, AV_OPT_TYPE_CONST, {.i64=HORZOPEN},   0, 0, FLAGS, "transition" },
178     {   "horzclose",  "horz close transition",  0, AV_OPT_TYPE_CONST, {.i64=HORZCLOSE},  0, 0, FLAGS, "transition" },
179     {   "dissolve",   "dissolve transition",    0, AV_OPT_TYPE_CONST, {.i64=DISSOLVE},   0, 0, FLAGS, "transition" },
180     {   "pixelize",   "pixelize transition",    0, AV_OPT_TYPE_CONST, {.i64=PIXELIZE},   0, 0, FLAGS, "transition" },
181     {   "diagtl",     "diag tl transition",     0, AV_OPT_TYPE_CONST, {.i64=DIAGTL},     0, 0, FLAGS, "transition" },
182     {   "diagtr",     "diag tr transition",     0, AV_OPT_TYPE_CONST, {.i64=DIAGTR},     0, 0, FLAGS, "transition" },
183     {   "diagbl",     "diag bl transition",     0, AV_OPT_TYPE_CONST, {.i64=DIAGBL},     0, 0, FLAGS, "transition" },
184     {   "diagbr",     "diag br transition",     0, AV_OPT_TYPE_CONST, {.i64=DIAGBR},     0, 0, FLAGS, "transition" },
185     {   "hlslice",    "hl slice transition",    0, AV_OPT_TYPE_CONST, {.i64=HLSLICE},    0, 0, FLAGS, "transition" },
186     {   "hrslice",    "hr slice transition",    0, AV_OPT_TYPE_CONST, {.i64=HRSLICE},    0, 0, FLAGS, "transition" },
187     {   "vuslice",    "vu slice transition",    0, AV_OPT_TYPE_CONST, {.i64=VUSLICE},    0, 0, FLAGS, "transition" },
188     {   "vdslice",    "vd slice transition",    0, AV_OPT_TYPE_CONST, {.i64=VDSLICE},    0, 0, FLAGS, "transition" },
189     {   "hblur",      "hblur transition",       0, AV_OPT_TYPE_CONST, {.i64=HBLUR},      0, 0, FLAGS, "transition" },
190     {   "fadegrays",  "fadegrays transition",   0, AV_OPT_TYPE_CONST, {.i64=FADEGRAYS},  0, 0, FLAGS, "transition" },
191     {   "wipetl",     "wipe tl transition",     0, AV_OPT_TYPE_CONST, {.i64=WIPETL},     0, 0, FLAGS, "transition" },
192     {   "wipetr",     "wipe tr transition",     0, AV_OPT_TYPE_CONST, {.i64=WIPETR},     0, 0, FLAGS, "transition" },
193     {   "wipebl",     "wipe bl transition",     0, AV_OPT_TYPE_CONST, {.i64=WIPEBL},     0, 0, FLAGS, "transition" },
194     {   "wipebr",     "wipe br transition",     0, AV_OPT_TYPE_CONST, {.i64=WIPEBR},     0, 0, FLAGS, "transition" },
195     {   "squeezeh",   "squeeze h transition",   0, AV_OPT_TYPE_CONST, {.i64=SQUEEZEH},   0, 0, FLAGS, "transition" },
196     {   "squeezev",   "squeeze v transition",   0, AV_OPT_TYPE_CONST, {.i64=SQUEEZEV},   0, 0, FLAGS, "transition" },
197     {   "zoomin",     "zoom in transition",     0, AV_OPT_TYPE_CONST, {.i64=ZOOMIN},     0, 0, FLAGS, "transition" },
198     {   "fadefast",   "fast fade transition",   0, AV_OPT_TYPE_CONST, {.i64=FADEFAST},   0, 0, FLAGS, "transition" },
199     {   "fadeslow",   "slow fade transition",   0, AV_OPT_TYPE_CONST, {.i64=FADESLOW},   0, 0, FLAGS, "transition" },
200     { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=1000000}, 0, 60000000, FLAGS },
201     { "offset",   "set cross fade start relative to first input stream", OFFSET(offset), AV_OPT_TYPE_DURATION, {.i64=0}, INT64_MIN, INT64_MAX, FLAGS },
202     { "expr",   "set expression for custom transition", OFFSET(custom_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
203     { NULL }
204 };
205 
206 AVFILTER_DEFINE_CLASS(xfade);
207 
208 #define CUSTOM_TRANSITION(name, type, div)                                           \
209 static void custom##name##_transition(AVFilterContext *ctx,                          \
210                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
211                             float progress,                                          \
212                             int slice_start, int slice_end, int jobnr)               \
213 {                                                                                    \
214     XFadeContext *s = ctx->priv;                                                     \
215     const int height = slice_end - slice_start;                                      \
216                                                                                      \
217     double values[VAR_VARS_NB];                                                      \
218     values[VAR_W] = out->width;                                                      \
219     values[VAR_H] = out->height;                                                     \
220     values[VAR_PROGRESS] = progress;                                                 \
221                                                                                      \
222     for (int p = 0; p < s->nb_planes; p++) {                                         \
223         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
224         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
225         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
226                                                                                      \
227         values[VAR_PLANE] = p;                                                       \
228                                                                                      \
229         for (int y = 0; y < height; y++) {                                           \
230             values[VAR_Y] = slice_start + y;                                         \
231             for (int x = 0; x < out->width; x++) {                                   \
232                 values[VAR_X] = x;                                                   \
233                 values[VAR_A] = xf0[x];                                              \
234                 values[VAR_B] = xf1[x];                                              \
235                 dst[x] = av_expr_eval(s->e, values, s);                              \
236             }                                                                        \
237                                                                                      \
238             dst += out->linesize[p] / div;                                           \
239             xf0 += a->linesize[p] / div;                                             \
240             xf1 += b->linesize[p] / div;                                             \
241         }                                                                            \
242     }                                                                                \
243 }
244 
245 CUSTOM_TRANSITION(8, uint8_t, 1)
246 CUSTOM_TRANSITION(16, uint16_t, 2)
247 
mix(float a,float b,float mix)248 static inline float mix(float a, float b, float mix)
249 {
250     return a * mix + b * (1.f - mix);
251 }
252 
fract(float a)253 static inline float fract(float a)
254 {
255     return a - floorf(a);
256 }
257 
smoothstep(float edge0,float edge1,float x)258 static inline float smoothstep(float edge0, float edge1, float x)
259 {
260     float t;
261 
262     t = av_clipf((x - edge0) / (edge1 - edge0), 0.f, 1.f);
263 
264     return t * t * (3.f - 2.f * t);
265 }
266 
267 #define FADE_TRANSITION(name, type, div)                                             \
268 static void fade##name##_transition(AVFilterContext *ctx,                            \
269                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
270                             float progress,                                          \
271                             int slice_start, int slice_end, int jobnr)               \
272 {                                                                                    \
273     XFadeContext *s = ctx->priv;                                                     \
274     const int height = slice_end - slice_start;                                      \
275                                                                                      \
276     for (int p = 0; p < s->nb_planes; p++) {                                         \
277         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
278         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
279         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
280                                                                                      \
281         for (int y = 0; y < height; y++) {                                           \
282             for (int x = 0; x < out->width; x++) {                                   \
283                 dst[x] = mix(xf0[x], xf1[x], progress);                              \
284             }                                                                        \
285                                                                                      \
286             dst += out->linesize[p] / div;                                           \
287             xf0 += a->linesize[p] / div;                                             \
288             xf1 += b->linesize[p] / div;                                             \
289         }                                                                            \
290     }                                                                                \
291 }
292 
293 FADE_TRANSITION(8, uint8_t, 1)
294 FADE_TRANSITION(16, uint16_t, 2)
295 
296 #define WIPELEFT_TRANSITION(name, type, div)                                         \
297 static void wipeleft##name##_transition(AVFilterContext *ctx,                        \
298                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
299                                 float progress,                                      \
300                                 int slice_start, int slice_end, int jobnr)           \
301 {                                                                                    \
302     XFadeContext *s = ctx->priv;                                                     \
303     const int height = slice_end - slice_start;                                      \
304     const int z = out->width * progress;                                             \
305                                                                                      \
306     for (int p = 0; p < s->nb_planes; p++) {                                         \
307         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
308         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
309         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
310                                                                                      \
311         for (int y = 0; y < height; y++) {                                           \
312             for (int x = 0; x < out->width; x++) {                                   \
313                 dst[x] = x > z ? xf1[x] : xf0[x];                                    \
314             }                                                                        \
315                                                                                      \
316             dst += out->linesize[p] / div;                                           \
317             xf0 += a->linesize[p] / div;                                             \
318             xf1 += b->linesize[p] / div;                                             \
319         }                                                                            \
320     }                                                                                \
321 }
322 
323 WIPELEFT_TRANSITION(8, uint8_t, 1)
324 WIPELEFT_TRANSITION(16, uint16_t, 2)
325 
326 #define WIPERIGHT_TRANSITION(name, type, div)                                        \
327 static void wiperight##name##_transition(AVFilterContext *ctx,                       \
328                                  const AVFrame *a, const AVFrame *b, AVFrame *out,   \
329                                  float progress,                                     \
330                                  int slice_start, int slice_end, int jobnr)          \
331 {                                                                                    \
332     XFadeContext *s = ctx->priv;                                                     \
333     const int height = slice_end - slice_start;                                      \
334     const int z = out->width * (1.f - progress);                                     \
335                                                                                      \
336     for (int p = 0; p < s->nb_planes; p++) {                                         \
337         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
338         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
339         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
340                                                                                      \
341         for (int y = 0; y < height; y++) {                                           \
342             for (int x = 0; x < out->width; x++) {                                   \
343                 dst[x] = x > z ? xf0[x] : xf1[x];                                    \
344             }                                                                        \
345                                                                                      \
346             dst += out->linesize[p] / div;                                           \
347             xf0 += a->linesize[p] / div;                                             \
348             xf1 += b->linesize[p] / div;                                             \
349         }                                                                            \
350     }                                                                                \
351 }
352 
353 WIPERIGHT_TRANSITION(8, uint8_t, 1)
354 WIPERIGHT_TRANSITION(16, uint16_t, 2)
355 
356 #define WIPEUP_TRANSITION(name, type, div)                                           \
357 static void wipeup##name##_transition(AVFilterContext *ctx,                          \
358                               const AVFrame *a, const AVFrame *b, AVFrame *out,      \
359                               float progress,                                        \
360                               int slice_start, int slice_end, int jobnr)             \
361 {                                                                                    \
362     XFadeContext *s = ctx->priv;                                                     \
363     const int height = slice_end - slice_start;                                      \
364     const int z = out->height * progress;                                            \
365                                                                                      \
366     for (int p = 0; p < s->nb_planes; p++) {                                         \
367         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
368         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
369         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
370                                                                                      \
371         for (int y = 0; y < height; y++) {                                           \
372             for (int x = 0; x < out->width; x++) {                                   \
373                 dst[x] = slice_start + y > z ? xf1[x] : xf0[x];                      \
374             }                                                                        \
375                                                                                      \
376             dst += out->linesize[p] / div;                                           \
377             xf0 += a->linesize[p] / div;                                             \
378             xf1 += b->linesize[p] / div;                                             \
379         }                                                                            \
380     }                                                                                \
381 }
382 
383 WIPEUP_TRANSITION(8, uint8_t, 1)
384 WIPEUP_TRANSITION(16, uint16_t, 2)
385 
386 #define WIPEDOWN_TRANSITION(name, type, div)                                         \
387 static void wipedown##name##_transition(AVFilterContext *ctx,                        \
388                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
389                                 float progress,                                      \
390                                 int slice_start, int slice_end, int jobnr)           \
391 {                                                                                    \
392     XFadeContext *s = ctx->priv;                                                     \
393     const int height = slice_end - slice_start;                                      \
394     const int z = out->height * (1.f - progress);                                    \
395                                                                                      \
396     for (int p = 0; p < s->nb_planes; p++) {                                         \
397         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
398         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
399         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
400                                                                                      \
401         for (int y = 0; y < height; y++) {                                           \
402             for (int x = 0; x < out->width; x++) {                                   \
403                 dst[x] = slice_start + y > z ? xf0[x] : xf1[x];                      \
404             }                                                                        \
405                                                                                      \
406             dst += out->linesize[p] / div;                                           \
407             xf0 += a->linesize[p] / div;                                             \
408             xf1 += b->linesize[p] / div;                                             \
409         }                                                                            \
410     }                                                                                \
411 }
412 
413 WIPEDOWN_TRANSITION(8, uint8_t, 1)
414 WIPEDOWN_TRANSITION(16, uint16_t, 2)
415 
416 #define SLIDELEFT_TRANSITION(name, type, div)                                        \
417 static void slideleft##name##_transition(AVFilterContext *ctx,                       \
418                                  const AVFrame *a, const AVFrame *b, AVFrame *out,   \
419                                  float progress,                                     \
420                                  int slice_start, int slice_end, int jobnr)          \
421 {                                                                                    \
422     XFadeContext *s = ctx->priv;                                                     \
423     const int height = slice_end - slice_start;                                      \
424     const int width = out->width;                                                    \
425     const int z = -progress * width;                                                 \
426                                                                                      \
427     for (int p = 0; p < s->nb_planes; p++) {                                         \
428         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
429         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
430         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
431                                                                                      \
432         for (int y = 0; y < height; y++) {                                           \
433             for (int x = 0; x < width; x++) {                                        \
434                 const int zx = z + x;                                                \
435                 const int zz = zx % width + width * (zx < 0);                        \
436                 dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz];              \
437             }                                                                        \
438                                                                                      \
439             dst += out->linesize[p] / div;                                           \
440             xf0 += a->linesize[p] / div;                                             \
441             xf1 += b->linesize[p] / div;                                             \
442         }                                                                            \
443     }                                                                                \
444 }
445 
446 SLIDELEFT_TRANSITION(8, uint8_t, 1)
447 SLIDELEFT_TRANSITION(16, uint16_t, 2)
448 
449 #define SLIDERIGHT_TRANSITION(name, type, div)                                       \
450 static void slideright##name##_transition(AVFilterContext *ctx,                      \
451                                   const AVFrame *a, const AVFrame *b, AVFrame *out,  \
452                                   float progress,                                    \
453                                   int slice_start, int slice_end, int jobnr)         \
454 {                                                                                    \
455     XFadeContext *s = ctx->priv;                                                     \
456     const int height = slice_end - slice_start;                                      \
457     const int width = out->width;                                                    \
458     const int z = progress * width;                                                  \
459                                                                                      \
460     for (int p = 0; p < s->nb_planes; p++) {                                         \
461         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
462         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
463         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
464                                                                                      \
465         for (int y = 0; y < height; y++) {                                           \
466             for (int x = 0; x < out->width; x++) {                                   \
467                 const int zx = z + x;                                                \
468                 const int zz = zx % width + width * (zx < 0);                        \
469                 dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz];              \
470             }                                                                        \
471                                                                                      \
472             dst += out->linesize[p] / div;                                           \
473             xf0 += a->linesize[p] / div;                                             \
474             xf1 += b->linesize[p] / div;                                             \
475         }                                                                            \
476     }                                                                                \
477 }
478 
479 SLIDERIGHT_TRANSITION(8, uint8_t, 1)
480 SLIDERIGHT_TRANSITION(16, uint16_t, 2)
481 
482 #define SLIDEUP_TRANSITION(name, type, div)                                         \
483 static void slideup##name##_transition(AVFilterContext *ctx,                        \
484                                const AVFrame *a, const AVFrame *b, AVFrame *out,    \
485                                float progress,                                      \
486                                int slice_start, int slice_end, int jobnr)           \
487 {                                                                                   \
488     XFadeContext *s = ctx->priv;                                                    \
489     const int height = out->height;                                                 \
490     const int z = -progress * height;                                               \
491                                                                                     \
492     for (int p = 0; p < s->nb_planes; p++) {                                        \
493         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);        \
494                                                                                     \
495         for (int y = slice_start; y < slice_end; y++) {                             \
496             const int zy = z + y;                                                   \
497             const int zz = zy % height + height * (zy < 0);                         \
498             const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]);     \
499             const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]);     \
500                                                                                     \
501             for (int x = 0; x < out->width; x++) {                                  \
502                 dst[x] = (zy >= 0) && (zy < height) ? xf1[x] : xf0[x];              \
503             }                                                                       \
504                                                                                     \
505             dst += out->linesize[p] / div;                                          \
506         }                                                                           \
507     }                                                                               \
508 }
509 
510 SLIDEUP_TRANSITION(8, uint8_t, 1)
511 SLIDEUP_TRANSITION(16, uint16_t, 2)
512 
513 #define SLIDEDOWN_TRANSITION(name, type, div)                                       \
514 static void slidedown##name##_transition(AVFilterContext *ctx,                      \
515                                  const AVFrame *a, const AVFrame *b, AVFrame *out,  \
516                                  float progress,                                    \
517                                  int slice_start, int slice_end, int jobnr)         \
518 {                                                                                   \
519     XFadeContext *s = ctx->priv;                                                    \
520     const int height = out->height;                                                 \
521     const int z = progress * height;                                                \
522                                                                                     \
523     for (int p = 0; p < s->nb_planes; p++) {                                        \
524         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);        \
525                                                                                     \
526         for (int y = slice_start; y < slice_end; y++) {                             \
527             const int zy = z + y;                                                   \
528             const int zz = zy % height + height * (zy < 0);                         \
529             const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]);     \
530             const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]);     \
531                                                                                     \
532             for (int x = 0; x < out->width; x++) {                                  \
533                 dst[x] = (zy >= 0) && (zy < height) ? xf1[x] : xf0[x];              \
534             }                                                                       \
535                                                                                     \
536             dst += out->linesize[p] / div;                                          \
537         }                                                                           \
538     }                                                                               \
539 }
540 
541 SLIDEDOWN_TRANSITION(8, uint8_t, 1)
542 SLIDEDOWN_TRANSITION(16, uint16_t, 2)
543 
544 #define CIRCLECROP_TRANSITION(name, type, div)                                      \
545 static void circlecrop##name##_transition(AVFilterContext *ctx,                     \
546                                  const AVFrame *a, const AVFrame *b, AVFrame *out,  \
547                                  float progress,                                    \
548                                  int slice_start, int slice_end, int jobnr)         \
549 {                                                                                   \
550     XFadeContext *s = ctx->priv;                                                    \
551     const int width = out->width;                                                   \
552     const int height = out->height;                                                 \
553     float z = powf(2.f * fabsf(progress - 0.5f), 3.f) * hypotf(width/2, height/2);  \
554                                                                                     \
555     for (int p = 0; p < s->nb_planes; p++) {                                        \
556         const int bg = s->black[p];                                                 \
557         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);        \
558                                                                                     \
559         for (int y = slice_start; y < slice_end; y++) {                             \
560             const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);      \
561             const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);      \
562                                                                                     \
563             for (int x = 0; x < width; x++) {                                       \
564                 float dist = hypotf(x - width / 2, y - height / 2);                 \
565                 int val = progress < 0.5f ? xf1[x] : xf0[x];                        \
566                 dst[x] = (z < dist) ? bg : val;                                     \
567             }                                                                       \
568                                                                                     \
569             dst += out->linesize[p] / div;                                          \
570         }                                                                           \
571     }                                                                               \
572 }
573 
574 CIRCLECROP_TRANSITION(8, uint8_t, 1)
575 CIRCLECROP_TRANSITION(16, uint16_t, 2)
576 
577 #define RECTCROP_TRANSITION(name, type, div)                                        \
578 static void rectcrop##name##_transition(AVFilterContext *ctx,                       \
579                                  const AVFrame *a, const AVFrame *b, AVFrame *out,  \
580                                  float progress,                                    \
581                                  int slice_start, int slice_end, int jobnr)         \
582 {                                                                                   \
583     XFadeContext *s = ctx->priv;                                                    \
584     const int width = out->width;                                                   \
585     const int height = out->height;                                                 \
586     int zh = fabsf(progress - 0.5f) * height;                                       \
587     int zw = fabsf(progress - 0.5f) * width;                                        \
588                                                                                     \
589     for (int p = 0; p < s->nb_planes; p++) {                                        \
590         const int bg = s->black[p];                                                 \
591         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);        \
592                                                                                     \
593         for (int y = slice_start; y < slice_end; y++) {                             \
594             const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);      \
595             const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);      \
596                                                                                     \
597             for (int x = 0; x < width; x++) {                                       \
598                 int dist = FFABS(x - width  / 2) < zw &&                            \
599                            FFABS(y - height / 2) < zh;                              \
600                 int val = progress < 0.5f ? xf1[x] : xf0[x];                        \
601                 dst[x] = !dist ? bg : val;                                          \
602             }                                                                       \
603                                                                                     \
604             dst += out->linesize[p] / div;                                          \
605         }                                                                           \
606     }                                                                               \
607 }
608 
609 RECTCROP_TRANSITION(8, uint8_t, 1)
610 RECTCROP_TRANSITION(16, uint16_t, 2)
611 
612 #define DISTANCE_TRANSITION(name, type, div)                                        \
613 static void distance##name##_transition(AVFilterContext *ctx,                       \
614                                  const AVFrame *a, const AVFrame *b, AVFrame *out,  \
615                                  float progress,                                    \
616                                  int slice_start, int slice_end, int jobnr)         \
617 {                                                                                   \
618     XFadeContext *s = ctx->priv;                                                    \
619     const int width = out->width;                                                   \
620     const float max = s->max_value;                                                 \
621                                                                                     \
622     for (int y = slice_start; y < slice_end; y++) {                                 \
623         for (int x = 0; x < width; x++) {                                           \
624             float dist = 0.f;                                                       \
625             for (int p = 0; p < s->nb_planes; p++) {                                \
626                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);  \
627                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);  \
628                                                                                     \
629                 dist += (xf0[x] / max - xf1[x] / max) *                             \
630                         (xf0[x] / max - xf1[x] / max);                              \
631             }                                                                       \
632                                                                                     \
633             dist = sqrtf(dist) <= progress;                                         \
634             for (int p = 0; p < s->nb_planes; p++) {                                \
635                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);  \
636                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);  \
637                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);          \
638                 dst[x] = mix(mix(xf0[x], xf1[x], dist), xf1[x], progress);          \
639             }                                                                       \
640         }                                                                           \
641     }                                                                               \
642 }
643 
644 DISTANCE_TRANSITION(8, uint8_t, 1)
645 DISTANCE_TRANSITION(16, uint16_t, 2)
646 
647 #define FADEBLACK_TRANSITION(name, type, div)                                        \
648 static void fadeblack##name##_transition(AVFilterContext *ctx,                       \
649                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
650                             float progress,                                          \
651                             int slice_start, int slice_end, int jobnr)               \
652 {                                                                                    \
653     XFadeContext *s = ctx->priv;                                                     \
654     const int height = slice_end - slice_start;                                      \
655     const float phase = 0.2f;                                                        \
656                                                                                      \
657     for (int p = 0; p < s->nb_planes; p++) {                                         \
658         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
659         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
660         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
661         const int bg = s->black[p];                                                  \
662                                                                                      \
663         for (int y = 0; y < height; y++) {                                           \
664             for (int x = 0; x < out->width; x++) {                                   \
665                 dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)),  \
666                          mix(bg, xf1[x], smoothstep(phase, 1.f, progress)),          \
667                              progress);                                              \
668             }                                                                        \
669                                                                                      \
670             dst += out->linesize[p] / div;                                           \
671             xf0 += a->linesize[p] / div;                                             \
672             xf1 += b->linesize[p] / div;                                             \
673         }                                                                            \
674     }                                                                                \
675 }
676 
677 FADEBLACK_TRANSITION(8, uint8_t, 1)
678 FADEBLACK_TRANSITION(16, uint16_t, 2)
679 
680 #define FADEWHITE_TRANSITION(name, type, div)                                        \
681 static void fadewhite##name##_transition(AVFilterContext *ctx,                       \
682                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
683                             float progress,                                          \
684                             int slice_start, int slice_end, int jobnr)               \
685 {                                                                                    \
686     XFadeContext *s = ctx->priv;                                                     \
687     const int height = slice_end - slice_start;                                      \
688     const float phase = 0.2f;                                                        \
689                                                                                      \
690     for (int p = 0; p < s->nb_planes; p++) {                                         \
691         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
692         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
693         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
694         const int bg = s->white[p];                                                  \
695                                                                                      \
696         for (int y = 0; y < height; y++) {                                           \
697             for (int x = 0; x < out->width; x++) {                                   \
698                 dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)),  \
699                          mix(bg, xf1[x], smoothstep(phase, 1.f, progress)),          \
700                              progress);                                              \
701             }                                                                        \
702                                                                                      \
703             dst += out->linesize[p] / div;                                           \
704             xf0 += a->linesize[p] / div;                                             \
705             xf1 += b->linesize[p] / div;                                             \
706         }                                                                            \
707     }                                                                                \
708 }
709 
710 FADEWHITE_TRANSITION(8, uint8_t, 1)
711 FADEWHITE_TRANSITION(16, uint16_t, 2)
712 
713 #define RADIAL_TRANSITION(name, type, div)                                           \
714 static void radial##name##_transition(AVFilterContext *ctx,                          \
715                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
716                             float progress,                                          \
717                             int slice_start, int slice_end, int jobnr)               \
718 {                                                                                    \
719     XFadeContext *s = ctx->priv;                                                     \
720     const int width = out->width;                                                    \
721     const int height = out->height;                                                  \
722                                                                                      \
723     for (int y = slice_start; y < slice_end; y++) {                                  \
724         for (int x = 0; x < width; x++) {                                            \
725             const float smooth = atan2f(x - width / 2, y - height / 2) -             \
726                                  (progress - 0.5f) * (M_PI * 2.5f);                  \
727             for (int p = 0; p < s->nb_planes; p++) {                                 \
728                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
729                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
730                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
731                                                                                      \
732                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
733             }                                                                        \
734         }                                                                            \
735     }                                                                                \
736 }
737 
738 RADIAL_TRANSITION(8, uint8_t, 1)
739 RADIAL_TRANSITION(16, uint16_t, 2)
740 
741 #define SMOOTHLEFT_TRANSITION(name, type, div)                                       \
742 static void smoothleft##name##_transition(AVFilterContext *ctx,                      \
743                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
744                             float progress,                                          \
745                             int slice_start, int slice_end, int jobnr)               \
746 {                                                                                    \
747     XFadeContext *s = ctx->priv;                                                     \
748     const int width = out->width;                                                    \
749     const float w = width;                                                           \
750                                                                                      \
751     for (int y = slice_start; y < slice_end; y++) {                                  \
752         for (int x = 0; x < width; x++) {                                            \
753             const float smooth = 1.f + x / w - progress * 2.f;                       \
754                                                                                      \
755             for (int p = 0; p < s->nb_planes; p++) {                                 \
756                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
757                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
758                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
759                                                                                      \
760                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
761             }                                                                        \
762         }                                                                            \
763     }                                                                                \
764 }
765 
766 SMOOTHLEFT_TRANSITION(8, uint8_t, 1)
767 SMOOTHLEFT_TRANSITION(16, uint16_t, 2)
768 
769 #define SMOOTHRIGHT_TRANSITION(name, type, div)                                      \
770 static void smoothright##name##_transition(AVFilterContext *ctx,                     \
771                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
772                             float progress,                                          \
773                             int slice_start, int slice_end, int jobnr)               \
774 {                                                                                    \
775     XFadeContext *s = ctx->priv;                                                     \
776     const int width = out->width;                                                    \
777     const float w = width;                                                           \
778                                                                                      \
779     for (int y = slice_start; y < slice_end; y++) {                                  \
780         for (int x = 0; x < width; x++) {                                            \
781             const float smooth = 1.f + (w - 1 - x) / w - progress * 2.f;             \
782                                                                                      \
783             for (int p = 0; p < s->nb_planes; p++) {                                 \
784                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
785                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
786                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
787                                                                                      \
788                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
789             }                                                                        \
790         }                                                                            \
791     }                                                                                \
792 }
793 
794 SMOOTHRIGHT_TRANSITION(8, uint8_t, 1)
795 SMOOTHRIGHT_TRANSITION(16, uint16_t, 2)
796 
797 #define SMOOTHUP_TRANSITION(name, type, div)                                         \
798 static void smoothup##name##_transition(AVFilterContext *ctx,                        \
799                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
800                             float progress,                                          \
801                             int slice_start, int slice_end, int jobnr)               \
802 {                                                                                    \
803     XFadeContext *s = ctx->priv;                                                     \
804     const int width = out->width;                                                    \
805     const float h = out->height;                                                     \
806                                                                                      \
807     for (int y = slice_start; y < slice_end; y++) {                                  \
808         const float smooth = 1.f + y / h - progress * 2.f;                           \
809         for (int x = 0; x < width; x++) {                                            \
810             for (int p = 0; p < s->nb_planes; p++) {                                 \
811                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
812                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
813                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
814                                                                                      \
815                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
816             }                                                                        \
817         }                                                                            \
818     }                                                                                \
819 }
820 
821 SMOOTHUP_TRANSITION(8, uint8_t, 1)
822 SMOOTHUP_TRANSITION(16, uint16_t, 2)
823 
824 #define SMOOTHDOWN_TRANSITION(name, type, div)                                       \
825 static void smoothdown##name##_transition(AVFilterContext *ctx,                      \
826                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
827                             float progress,                                          \
828                             int slice_start, int slice_end, int jobnr)               \
829 {                                                                                    \
830     XFadeContext *s = ctx->priv;                                                     \
831     const int width = out->width;                                                    \
832     const float h = out->height;                                                     \
833                                                                                      \
834     for (int y = slice_start; y < slice_end; y++) {                                  \
835         const float smooth = 1.f + (h - 1 - y) / h - progress * 2.f;                 \
836         for (int x = 0; x < width; x++) {                                            \
837             for (int p = 0; p < s->nb_planes; p++) {                                 \
838                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
839                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
840                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
841                                                                                      \
842                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
843             }                                                                        \
844         }                                                                            \
845     }                                                                                \
846 }
847 
848 SMOOTHDOWN_TRANSITION(8, uint8_t, 1)
849 SMOOTHDOWN_TRANSITION(16, uint16_t, 2)
850 
851 #define CIRCLEOPEN_TRANSITION(name, type, div)                                       \
852 static void circleopen##name##_transition(AVFilterContext *ctx,                      \
853                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
854                             float progress,                                          \
855                             int slice_start, int slice_end, int jobnr)               \
856 {                                                                                    \
857     XFadeContext *s = ctx->priv;                                                     \
858     const int width = out->width;                                                    \
859     const int height = out->height;                                                  \
860     const float z = hypotf(width / 2, height / 2);                                   \
861     const float p = (progress - 0.5f) * 3.f;                                         \
862                                                                                      \
863     for (int y = slice_start; y < slice_end; y++) {                                  \
864         for (int x = 0; x < width; x++) {                                            \
865             const float smooth = hypotf(x - width / 2, y - height / 2) / z + p;      \
866             for (int p = 0; p < s->nb_planes; p++) {                                 \
867                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
868                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
869                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
870                                                                                      \
871                 dst[x] = mix(xf0[x], xf1[x], smoothstep(0.f, 1.f, smooth));          \
872             }                                                                        \
873         }                                                                            \
874     }                                                                                \
875 }
876 
877 CIRCLEOPEN_TRANSITION(8, uint8_t, 1)
878 CIRCLEOPEN_TRANSITION(16, uint16_t, 2)
879 
880 #define CIRCLECLOSE_TRANSITION(name, type, div)                                      \
881 static void circleclose##name##_transition(AVFilterContext *ctx,                     \
882                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
883                             float progress,                                          \
884                             int slice_start, int slice_end, int jobnr)               \
885 {                                                                                    \
886     XFadeContext *s = ctx->priv;                                                     \
887     const int width = out->width;                                                    \
888     const int height = out->height;                                                  \
889     const float z = hypotf(width / 2, height / 2);                                   \
890     const float p = (1.f - progress - 0.5f) * 3.f;                                   \
891                                                                                      \
892     for (int y = slice_start; y < slice_end; y++) {                                  \
893         for (int x = 0; x < width; x++) {                                            \
894             const float smooth = hypotf(x - width / 2, y - height / 2) / z + p;      \
895             for (int p = 0; p < s->nb_planes; p++) {                                 \
896                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
897                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
898                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
899                                                                                      \
900                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
901             }                                                                        \
902         }                                                                            \
903     }                                                                                \
904 }
905 
906 CIRCLECLOSE_TRANSITION(8, uint8_t, 1)
907 CIRCLECLOSE_TRANSITION(16, uint16_t, 2)
908 
909 #define VERTOPEN_TRANSITION(name, type, div)                                         \
910 static void vertopen##name##_transition(AVFilterContext *ctx,                        \
911                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
912                             float progress,                                          \
913                             int slice_start, int slice_end, int jobnr)               \
914 {                                                                                    \
915     XFadeContext *s = ctx->priv;                                                     \
916     const int width = out->width;                                                    \
917     const float w2 = out->width / 2;                                                 \
918                                                                                      \
919     for (int y = slice_start; y < slice_end; y++) {                                  \
920         for (int x = 0; x < width; x++) {                                            \
921             const float smooth = 2.f - fabsf((x - w2) / w2) - progress * 2.f;        \
922             for (int p = 0; p < s->nb_planes; p++) {                                 \
923                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
924                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
925                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
926                                                                                      \
927                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
928             }                                                                        \
929         }                                                                            \
930     }                                                                                \
931 }
932 
933 VERTOPEN_TRANSITION(8, uint8_t, 1)
934 VERTOPEN_TRANSITION(16, uint16_t, 2)
935 
936 #define VERTCLOSE_TRANSITION(name, type, div)                                        \
937 static void vertclose##name##_transition(AVFilterContext *ctx,                       \
938                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
939                             float progress,                                          \
940                             int slice_start, int slice_end, int jobnr)               \
941 {                                                                                    \
942     XFadeContext *s = ctx->priv;                                                     \
943     const int width = out->width;                                                    \
944     const float w2 = out->width / 2;                                                 \
945                                                                                      \
946     for (int y = slice_start; y < slice_end; y++) {                                  \
947         for (int x = 0; x < width; x++) {                                            \
948             const float smooth = 1.f + fabsf((x - w2) / w2) - progress * 2.f;        \
949             for (int p = 0; p < s->nb_planes; p++) {                                 \
950                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
951                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
952                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
953                                                                                      \
954                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
955             }                                                                        \
956         }                                                                            \
957     }                                                                                \
958 }
959 
960 VERTCLOSE_TRANSITION(8, uint8_t, 1)
961 VERTCLOSE_TRANSITION(16, uint16_t, 2)
962 
963 #define HORZOPEN_TRANSITION(name, type, div)                                         \
964 static void horzopen##name##_transition(AVFilterContext *ctx,                        \
965                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
966                             float progress,                                          \
967                             int slice_start, int slice_end, int jobnr)               \
968 {                                                                                    \
969     XFadeContext *s = ctx->priv;                                                     \
970     const int width = out->width;                                                    \
971     const float h2 = out->height / 2;                                                \
972                                                                                      \
973     for (int y = slice_start; y < slice_end; y++) {                                  \
974         const float smooth = 2.f - fabsf((y - h2) / h2) - progress * 2.f;            \
975         for (int x = 0; x < width; x++) {                                            \
976             for (int p = 0; p < s->nb_planes; p++) {                                 \
977                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
978                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
979                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
980                                                                                      \
981                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
982             }                                                                        \
983         }                                                                            \
984     }                                                                                \
985 }
986 
987 HORZOPEN_TRANSITION(8, uint8_t, 1)
988 HORZOPEN_TRANSITION(16, uint16_t, 2)
989 
990 #define HORZCLOSE_TRANSITION(name, type, div)                                        \
991 static void horzclose##name##_transition(AVFilterContext *ctx,                       \
992                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
993                             float progress,                                          \
994                             int slice_start, int slice_end, int jobnr)               \
995 {                                                                                    \
996     XFadeContext *s = ctx->priv;                                                     \
997     const int width = out->width;                                                    \
998     const float h2 = out->height / 2;                                                \
999                                                                                      \
1000     for (int y = slice_start; y < slice_end; y++) {                                  \
1001         const float smooth = 1.f + fabsf((y - h2) / h2) - progress * 2.f;            \
1002         for (int x = 0; x < width; x++) {                                            \
1003             for (int p = 0; p < s->nb_planes; p++) {                                 \
1004                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1005                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1006                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1007                                                                                      \
1008                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
1009             }                                                                        \
1010         }                                                                            \
1011     }                                                                                \
1012 }
1013 
1014 HORZCLOSE_TRANSITION(8, uint8_t, 1)
1015 HORZCLOSE_TRANSITION(16, uint16_t, 2)
1016 
frand(int x,int y)1017 static float frand(int x, int y)
1018 {
1019     const float r = sinf(x * 12.9898f + y * 78.233f) * 43758.545f;
1020 
1021     return r - floorf(r);
1022 }
1023 
1024 #define DISSOLVE_TRANSITION(name, type, div)                                         \
1025 static void dissolve##name##_transition(AVFilterContext *ctx,                        \
1026                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1027                             float progress,                                          \
1028                             int slice_start, int slice_end, int jobnr)               \
1029 {                                                                                    \
1030     XFadeContext *s = ctx->priv;                                                     \
1031     const int width = out->width;                                                    \
1032                                                                                      \
1033     for (int y = slice_start; y < slice_end; y++) {                                  \
1034         for (int x = 0; x < width; x++) {                                            \
1035             const float smooth = frand(x, y) * 2.f + progress * 2.f - 1.5f;          \
1036             for (int p = 0; p < s->nb_planes; p++) {                                 \
1037                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1038                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1039                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1040                                                                                      \
1041                 dst[x] = smooth >= 0.5f ? xf0[x] : xf1[x];                           \
1042             }                                                                        \
1043         }                                                                            \
1044     }                                                                                \
1045 }
1046 
1047 DISSOLVE_TRANSITION(8, uint8_t, 1)
1048 DISSOLVE_TRANSITION(16, uint16_t, 2)
1049 
1050 #define PIXELIZE_TRANSITION(name, type, div)                                         \
1051 static void pixelize##name##_transition(AVFilterContext *ctx,                        \
1052                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1053                             float progress,                                          \
1054                             int slice_start, int slice_end, int jobnr)               \
1055 {                                                                                    \
1056     XFadeContext *s = ctx->priv;                                                     \
1057     const int w = out->width;                                                        \
1058     const int h = out->height;                                                       \
1059     const float d = fminf(progress, 1.f - progress);                                 \
1060     const float dist = ceilf(d * 50.f) / 50.f;                                       \
1061     const float sqx = 2.f * dist * FFMIN(w, h) / 20.f;                               \
1062     const float sqy = 2.f * dist * FFMIN(w, h) / 20.f;                               \
1063                                                                                      \
1064     for (int y = slice_start; y < slice_end; y++) {                                  \
1065         for (int x = 0; x < w; x++) {                                                \
1066             int sx = dist > 0.f ? FFMIN((floorf(x / sqx) + .5f) * sqx, w - 1) : x;   \
1067             int sy = dist > 0.f ? FFMIN((floorf(y / sqy) + .5f) * sqy, h - 1) : y;   \
1068             for (int p = 0; p < s->nb_planes; p++) {                                 \
1069                 const type *xf0 = (const type *)(a->data[p] + sy * a->linesize[p]);  \
1070                 const type *xf1 = (const type *)(b->data[p] + sy * b->linesize[p]);  \
1071                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1072                                                                                      \
1073                 dst[x] = mix(xf0[sx], xf1[sx], progress);                            \
1074             }                                                                        \
1075         }                                                                            \
1076     }                                                                                \
1077 }
1078 
1079 PIXELIZE_TRANSITION(8, uint8_t, 1)
1080 PIXELIZE_TRANSITION(16, uint16_t, 2)
1081 
1082 #define DIAGTL_TRANSITION(name, type, div)                                           \
1083 static void diagtl##name##_transition(AVFilterContext *ctx,                          \
1084                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1085                             float progress,                                          \
1086                             int slice_start, int slice_end, int jobnr)               \
1087 {                                                                                    \
1088     XFadeContext *s = ctx->priv;                                                     \
1089     const int width = out->width;                                                    \
1090     const float w = width;                                                           \
1091     const float h = out->height;                                                     \
1092                                                                                      \
1093     for (int y = slice_start; y < slice_end; y++) {                                  \
1094         for (int x = 0; x < width; x++) {                                            \
1095             const float smooth = 1.f + x / w * y / h - progress * 2.f;               \
1096                                                                                      \
1097             for (int p = 0; p < s->nb_planes; p++) {                                 \
1098                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1099                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1100                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1101                                                                                      \
1102                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
1103             }                                                                        \
1104         }                                                                            \
1105     }                                                                                \
1106 }
1107 
1108 DIAGTL_TRANSITION(8, uint8_t, 1)
1109 DIAGTL_TRANSITION(16, uint16_t, 2)
1110 
1111 #define DIAGTR_TRANSITION(name, type, div)                                           \
1112 static void diagtr##name##_transition(AVFilterContext *ctx,                          \
1113                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1114                             float progress,                                          \
1115                             int slice_start, int slice_end, int jobnr)               \
1116 {                                                                                    \
1117     XFadeContext *s = ctx->priv;                                                     \
1118     const int width = out->width;                                                    \
1119     const float w = width;                                                           \
1120     const float h = out->height;                                                     \
1121                                                                                      \
1122     for (int y = slice_start; y < slice_end; y++) {                                  \
1123         for (int x = 0; x < width; x++) {                                            \
1124             const float smooth = 1.f + (w - 1 - x) / w * y / h - progress * 2.f;     \
1125                                                                                      \
1126             for (int p = 0; p < s->nb_planes; p++) {                                 \
1127                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1128                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1129                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1130                                                                                      \
1131                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
1132             }                                                                        \
1133         }                                                                            \
1134     }                                                                                \
1135 }
1136 
1137 DIAGTR_TRANSITION(8, uint8_t, 1)
1138 DIAGTR_TRANSITION(16, uint16_t, 2)
1139 
1140 #define DIAGBL_TRANSITION(name, type, div)                                           \
1141 static void diagbl##name##_transition(AVFilterContext *ctx,                          \
1142                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1143                             float progress,                                          \
1144                             int slice_start, int slice_end, int jobnr)               \
1145 {                                                                                    \
1146     XFadeContext *s = ctx->priv;                                                     \
1147     const int width = out->width;                                                    \
1148     const float w = width;                                                           \
1149     const float h = out->height;                                                     \
1150                                                                                      \
1151     for (int y = slice_start; y < slice_end; y++) {                                  \
1152         for (int x = 0; x < width; x++) {                                            \
1153             const float smooth = 1.f + x / w * (h - 1 - y) / h - progress * 2.f;     \
1154                                                                                      \
1155             for (int p = 0; p < s->nb_planes; p++) {                                 \
1156                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1157                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1158                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1159                                                                                      \
1160                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
1161             }                                                                        \
1162         }                                                                            \
1163     }                                                                                \
1164 }
1165 
1166 DIAGBL_TRANSITION(8, uint8_t, 1)
1167 DIAGBL_TRANSITION(16, uint16_t, 2)
1168 
1169 #define DIAGBR_TRANSITION(name, type, div)                                           \
1170 static void diagbr##name##_transition(AVFilterContext *ctx,                          \
1171                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1172                             float progress,                                          \
1173                             int slice_start, int slice_end, int jobnr)               \
1174 {                                                                                    \
1175     XFadeContext *s = ctx->priv;                                                     \
1176     const int width = out->width;                                                    \
1177     const float w = width;                                                           \
1178     const float h = out->height;                                                     \
1179                                                                                      \
1180     for (int y = slice_start; y < slice_end; y++) {                                  \
1181         for (int x = 0; x < width; x++) {                                            \
1182             const float smooth = 1.f + (w - 1 - x) / w * (h - 1 - y) / h -           \
1183                                  progress * 2.f;                                     \
1184                                                                                      \
1185             for (int p = 0; p < s->nb_planes; p++) {                                 \
1186                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1187                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1188                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1189                                                                                      \
1190                 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth));          \
1191             }                                                                        \
1192         }                                                                            \
1193     }                                                                                \
1194 }
1195 
1196 DIAGBR_TRANSITION(8, uint8_t, 1)
1197 DIAGBR_TRANSITION(16, uint16_t, 2)
1198 
1199 #define HLSLICE_TRANSITION(name, type, div)                                          \
1200 static void hlslice##name##_transition(AVFilterContext *ctx,                         \
1201                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1202                             float progress,                                          \
1203                             int slice_start, int slice_end, int jobnr)               \
1204 {                                                                                    \
1205     XFadeContext *s = ctx->priv;                                                     \
1206     const int width = out->width;                                                    \
1207     const float w = width;                                                           \
1208                                                                                      \
1209     for (int y = slice_start; y < slice_end; y++) {                                  \
1210         for (int x = 0; x < width; x++) {                                            \
1211             const float smooth = smoothstep(-0.5f, 0.f, x / w - progress * 1.5f);    \
1212             const float ss = smooth <= fract(10.f * x / w) ? 0.f : 1.f;              \
1213                                                                                      \
1214             for (int p = 0; p < s->nb_planes; p++) {                                 \
1215                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1216                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1217                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1218                                                                                      \
1219                 dst[x] = mix(xf1[x], xf0[x], ss);                                    \
1220             }                                                                        \
1221         }                                                                            \
1222     }                                                                                \
1223 }
1224 
1225 HLSLICE_TRANSITION(8, uint8_t, 1)
1226 HLSLICE_TRANSITION(16, uint16_t, 2)
1227 
1228 #define HRSLICE_TRANSITION(name, type, div)                                          \
1229 static void hrslice##name##_transition(AVFilterContext *ctx,                         \
1230                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1231                             float progress,                                          \
1232                             int slice_start, int slice_end, int jobnr)               \
1233 {                                                                                    \
1234     XFadeContext *s = ctx->priv;                                                     \
1235     const int width = out->width;                                                    \
1236     const float w = width;                                                           \
1237                                                                                      \
1238     for (int y = slice_start; y < slice_end; y++) {                                  \
1239         for (int x = 0; x < width; x++) {                                            \
1240             const float xx = (w - 1 - x) / w;                                        \
1241             const float smooth = smoothstep(-0.5f, 0.f, xx - progress * 1.5f);       \
1242             const float ss = smooth <= fract(10.f * xx) ? 0.f : 1.f;                 \
1243                                                                                      \
1244             for (int p = 0; p < s->nb_planes; p++) {                                 \
1245                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1246                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1247                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1248                                                                                      \
1249                 dst[x] = mix(xf1[x], xf0[x], ss);                                    \
1250             }                                                                        \
1251         }                                                                            \
1252     }                                                                                \
1253 }
1254 
1255 HRSLICE_TRANSITION(8, uint8_t, 1)
1256 HRSLICE_TRANSITION(16, uint16_t, 2)
1257 
1258 #define VUSLICE_TRANSITION(name, type, div)                                          \
1259 static void vuslice##name##_transition(AVFilterContext *ctx,                         \
1260                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1261                             float progress,                                          \
1262                             int slice_start, int slice_end, int jobnr)               \
1263 {                                                                                    \
1264     XFadeContext *s = ctx->priv;                                                     \
1265     const int width = out->width;                                                    \
1266     const float h = out->height;                                                     \
1267                                                                                      \
1268     for (int y = slice_start; y < slice_end; y++) {                                  \
1269          const float smooth = smoothstep(-0.5f, 0.f, y / h - progress * 1.5f);       \
1270          const float ss = smooth <= fract(10.f * y / h) ? 0.f : 1.f;                 \
1271                                                                                      \
1272          for (int x = 0; x < width; x++) {                                           \
1273             for (int p = 0; p < s->nb_planes; p++) {                                 \
1274                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1275                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1276                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1277                                                                                      \
1278                 dst[x] = mix(xf1[x], xf0[x], ss);                                    \
1279             }                                                                        \
1280         }                                                                            \
1281     }                                                                                \
1282 }
1283 
1284 VUSLICE_TRANSITION(8, uint8_t, 1)
1285 VUSLICE_TRANSITION(16, uint16_t, 2)
1286 
1287 #define VDSLICE_TRANSITION(name, type, div)                                          \
1288 static void vdslice##name##_transition(AVFilterContext *ctx,                         \
1289                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1290                             float progress,                                          \
1291                             int slice_start, int slice_end, int jobnr)               \
1292 {                                                                                    \
1293     XFadeContext *s = ctx->priv;                                                     \
1294     const int width = out->width;                                                    \
1295     const float h = out->height;                                                     \
1296                                                                                      \
1297     for (int y = slice_start; y < slice_end; y++) {                                  \
1298          const float yy = (h - 1 - y) / h;                                           \
1299          const float smooth = smoothstep(-0.5f, 0.f, yy - progress * 1.5f);          \
1300          const float ss = smooth <= fract(10.f * yy) ? 0.f : 1.f;                    \
1301                                                                                      \
1302          for (int x = 0; x < width; x++) {                                           \
1303             for (int p = 0; p < s->nb_planes; p++) {                                 \
1304                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1305                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1306                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1307                                                                                      \
1308                 dst[x] = mix(xf1[x], xf0[x], ss);                                    \
1309             }                                                                        \
1310         }                                                                            \
1311     }                                                                                \
1312 }
1313 
1314 VDSLICE_TRANSITION(8, uint8_t, 1)
1315 VDSLICE_TRANSITION(16, uint16_t, 2)
1316 
1317 #define HBLUR_TRANSITION(name, type, div)                                            \
1318 static void hblur##name##_transition(AVFilterContext *ctx,                           \
1319                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1320                             float progress,                                          \
1321                             int slice_start, int slice_end, int jobnr)               \
1322 {                                                                                    \
1323     XFadeContext *s = ctx->priv;                                                     \
1324     const int width = out->width;                                                    \
1325     const float prog = progress <= 0.5f ? progress * 2.f : (1.f - progress) * 2.f;   \
1326     const int size = 1 + (width / 2) * prog;                                         \
1327                                                                                      \
1328     for (int y = slice_start; y < slice_end; y++) {                                  \
1329         for (int p = 0; p < s->nb_planes; p++) {                                     \
1330             const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);       \
1331             const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);       \
1332             type *dst = (type *)(out->data[p] + y * out->linesize[p]);               \
1333             float sum0 = 0.f;                                                        \
1334             float sum1 = 0.f;                                                        \
1335             float cnt = size;                                                        \
1336                                                                                      \
1337             for (int x = 0; x < size; x++) {                                         \
1338                 sum0 += xf0[x];                                                      \
1339                 sum1 += xf1[x];                                                      \
1340             }                                                                        \
1341                                                                                      \
1342             for (int x = 0; x < width; x++) {                                        \
1343                 dst[x] = mix(sum0 / cnt, sum1 / cnt, progress);                      \
1344                                                                                      \
1345                 if (x + size < width) {                                              \
1346                     sum0 += xf0[x + size] - xf0[x];                                  \
1347                     sum1 += xf1[x + size] - xf1[x];                                  \
1348                 } else {                                                             \
1349                     sum0 -= xf0[x];                                                  \
1350                     sum1 -= xf1[x];                                                  \
1351                     cnt--;                                                           \
1352                 }                                                                    \
1353             }                                                                        \
1354         }                                                                            \
1355     }                                                                                \
1356 }
1357 
1358 HBLUR_TRANSITION(8, uint8_t, 1)
1359 HBLUR_TRANSITION(16, uint16_t, 2)
1360 
1361 #define FADEGRAYS_TRANSITION(name, type, div)                                        \
1362 static void fadegrays##name##_transition(AVFilterContext *ctx,                       \
1363                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1364                             float progress,                                          \
1365                             int slice_start, int slice_end, int jobnr)               \
1366 {                                                                                    \
1367     XFadeContext *s = ctx->priv;                                                     \
1368     const int width = out->width;                                                    \
1369     const int is_rgb = s->is_rgb;                                                    \
1370     const int mid = (s->max_value + 1) / 2;                                          \
1371     const float phase = 0.2f;                                                        \
1372                                                                                      \
1373     for (int y = slice_start; y < slice_end; y++) {                                  \
1374         for (int x = 0; x < width; x++) {                                            \
1375             int bg[2][4];                                                            \
1376             if (is_rgb) {                                                            \
1377                 for (int p = 0; p < s->nb_planes; p++) {                             \
1378                     const type *xf0 = (const type *)(a->data[p] +                    \
1379                                                      y * a->linesize[p]);            \
1380                     const type *xf1 = (const type *)(b->data[p] +                    \
1381                                                      y * b->linesize[p]);            \
1382                     if (p == 3) {                                                    \
1383                         bg[0][3] = xf0[x];                                           \
1384                         bg[1][3] = xf1[x];                                           \
1385                     } else  {                                                        \
1386                         bg[0][0] += xf0[x];                                          \
1387                         bg[1][0] += xf1[x];                                          \
1388                     }                                                                \
1389                 }                                                                    \
1390                 bg[0][0] = bg[0][0] / 3;                                             \
1391                 bg[1][0] = bg[1][0] / 3;                                             \
1392                 bg[0][1] = bg[0][2] = bg[0][0];                                      \
1393                 bg[1][1] = bg[1][2] = bg[1][0];                                      \
1394             } else {                                                                 \
1395                 const type *yf0 = (const type *)(a->data[0] +                        \
1396                                                  y * a->linesize[0]);                \
1397                 const type *yf1 = (const type *)(b->data[0] +                        \
1398                                                  y * a->linesize[0]);                \
1399                 bg[0][0] = yf0[x];                                                   \
1400                 bg[1][0] = yf1[x];                                                   \
1401                 if (s->nb_planes == 4) {                                             \
1402                     const type *af0 = (const type *)(a->data[3] +                    \
1403                                                      y * a->linesize[3]);            \
1404                     const type *af1 = (const type *)(b->data[3] +                    \
1405                                                      y * a->linesize[3]);            \
1406                     bg[0][3] = af0[x];                                               \
1407                     bg[1][3] = af1[x];                                               \
1408                 }                                                                    \
1409                 bg[0][1] = bg[1][1] = mid;                                           \
1410                 bg[0][2] = bg[1][2] = mid;                                           \
1411             }                                                                        \
1412                                                                                      \
1413             for (int p = 0; p < s->nb_planes; p++) {                                 \
1414                 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]);   \
1415                 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]);   \
1416                 type *dst = (type *)(out->data[p] + y * out->linesize[p]);           \
1417                                                                                      \
1418                 dst[x] = mix(mix(xf0[x], bg[0][p],                                   \
1419                                  smoothstep(1.f-phase, 1.f, progress)),              \
1420                          mix(bg[1][p], xf1[x], smoothstep(phase, 1.f, progress)),    \
1421                              progress);                                              \
1422             }                                                                        \
1423         }                                                                            \
1424     }                                                                                \
1425 }
1426 
1427 FADEGRAYS_TRANSITION(8, uint8_t, 1)
1428 FADEGRAYS_TRANSITION(16, uint16_t, 2)
1429 
1430 #define WIPETL_TRANSITION(name, type, div)                                           \
1431 static void wipetl##name##_transition(AVFilterContext *ctx,                          \
1432                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
1433                                 float progress,                                      \
1434                                 int slice_start, int slice_end, int jobnr)           \
1435 {                                                                                    \
1436     XFadeContext *s = ctx->priv;                                                     \
1437     const int height = slice_end - slice_start;                                      \
1438     const int zw = out->width * progress;                                            \
1439     const int zh = out->height * progress;                                           \
1440                                                                                      \
1441     for (int p = 0; p < s->nb_planes; p++) {                                         \
1442         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1443         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1444         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
1445                                                                                      \
1446         for (int y = 0; y < height; y++) {                                           \
1447             for (int x = 0; x < out->width; x++) {                                   \
1448                 dst[x] = slice_start + y <= zh &&                                    \
1449                          x <= zw ? xf0[x] : xf1[x];                                  \
1450             }                                                                        \
1451                                                                                      \
1452             dst += out->linesize[p] / div;                                           \
1453             xf0 += a->linesize[p] / div;                                             \
1454             xf1 += b->linesize[p] / div;                                             \
1455         }                                                                            \
1456     }                                                                                \
1457 }
1458 
1459 WIPETL_TRANSITION(8, uint8_t, 1)
1460 WIPETL_TRANSITION(16, uint16_t, 2)
1461 
1462 #define WIPETR_TRANSITION(name, type, div)                                           \
1463 static void wipetr##name##_transition(AVFilterContext *ctx,                          \
1464                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
1465                                 float progress,                                      \
1466                                 int slice_start, int slice_end, int jobnr)           \
1467 {                                                                                    \
1468     XFadeContext *s = ctx->priv;                                                     \
1469     const int height = slice_end - slice_start;                                      \
1470     const int zw = out->width * (1.f - progress);                                    \
1471     const int zh = out->height * progress;                                           \
1472                                                                                      \
1473     for (int p = 0; p < s->nb_planes; p++) {                                         \
1474         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1475         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1476         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
1477                                                                                      \
1478         for (int y = 0; y < height; y++) {                                           \
1479             for (int x = 0; x < out->width; x++) {                                   \
1480                 dst[x] = slice_start + y <= zh &&                                    \
1481                          x > zw ? xf0[x] : xf1[x];                                   \
1482             }                                                                        \
1483                                                                                      \
1484             dst += out->linesize[p] / div;                                           \
1485             xf0 += a->linesize[p] / div;                                             \
1486             xf1 += b->linesize[p] / div;                                             \
1487         }                                                                            \
1488     }                                                                                \
1489 }
1490 
1491 WIPETR_TRANSITION(8, uint8_t, 1)
1492 WIPETR_TRANSITION(16, uint16_t, 2)
1493 
1494 #define WIPEBL_TRANSITION(name, type, div)                                           \
1495 static void wipebl##name##_transition(AVFilterContext *ctx,                          \
1496                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
1497                                 float progress,                                      \
1498                                 int slice_start, int slice_end, int jobnr)           \
1499 {                                                                                    \
1500     XFadeContext *s = ctx->priv;                                                     \
1501     const int height = slice_end - slice_start;                                      \
1502     const int zw = out->width * progress;                                            \
1503     const int zh = out->height * (1.f - progress);                                   \
1504                                                                                      \
1505     for (int p = 0; p < s->nb_planes; p++) {                                         \
1506         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1507         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1508         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
1509                                                                                      \
1510         for (int y = 0; y < height; y++) {                                           \
1511             for (int x = 0; x < out->width; x++) {                                   \
1512                 dst[x] = slice_start + y > zh &&                                     \
1513                          x <= zw ? xf0[x] : xf1[x];                                  \
1514             }                                                                        \
1515                                                                                      \
1516             dst += out->linesize[p] / div;                                           \
1517             xf0 += a->linesize[p] / div;                                             \
1518             xf1 += b->linesize[p] / div;                                             \
1519         }                                                                            \
1520     }                                                                                \
1521 }
1522 
1523 WIPEBL_TRANSITION(8, uint8_t, 1)
1524 WIPEBL_TRANSITION(16, uint16_t, 2)
1525 
1526 #define WIPEBR_TRANSITION(name, type, div)                                           \
1527 static void wipebr##name##_transition(AVFilterContext *ctx,                          \
1528                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
1529                                 float progress,                                      \
1530                                 int slice_start, int slice_end, int jobnr)           \
1531 {                                                                                    \
1532     XFadeContext *s = ctx->priv;                                                     \
1533     const int height = slice_end - slice_start;                                      \
1534     const int zh = out->height * (1.f - progress);                                   \
1535     const int zw = out->width * (1.f - progress);                                    \
1536                                                                                      \
1537     for (int p = 0; p < s->nb_planes; p++) {                                         \
1538         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1539         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1540         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
1541                                                                                      \
1542         for (int y = 0; y < height; y++) {                                           \
1543             for (int x = 0; x < out->width; x++) {                                   \
1544                 dst[x] = slice_start + y > zh &&                                     \
1545                          x > zw ? xf0[x] : xf1[x];                                   \
1546             }                                                                        \
1547                                                                                      \
1548             dst += out->linesize[p] / div;                                           \
1549             xf0 += a->linesize[p] / div;                                             \
1550             xf1 += b->linesize[p] / div;                                             \
1551         }                                                                            \
1552     }                                                                                \
1553 }
1554 
1555 WIPEBR_TRANSITION(8, uint8_t, 1)
1556 WIPEBR_TRANSITION(16, uint16_t, 2)
1557 
1558 #define SQUEEZEH_TRANSITION(name, type, div)                                         \
1559 static void squeezeh##name##_transition(AVFilterContext *ctx,                        \
1560                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
1561                                 float progress,                                      \
1562                                 int slice_start, int slice_end, int jobnr)           \
1563 {                                                                                    \
1564     XFadeContext *s = ctx->priv;                                                     \
1565     const float h = out->height;                                                     \
1566     const int height = slice_end - slice_start;                                      \
1567                                                                                      \
1568     for (int p = 0; p < s->nb_planes; p++) {                                         \
1569         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1570         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
1571                                                                                      \
1572         for (int y = 0; y < height; y++) {                                           \
1573             const float z = .5f + ((slice_start + y) / h - .5f) / progress;          \
1574                                                                                      \
1575             if (z < 0.f || z > 1.f) {                                                \
1576                 for (int x = 0; x < out->width; x++)                                 \
1577                     dst[x] = xf1[x];                                                 \
1578             } else {                                                                 \
1579                 const int yy = lrintf(z * (h - 1.f));                                \
1580                 const type *xf0 = (const type *)(a->data[p] + yy * a->linesize[p]);  \
1581                                                                                      \
1582                 for (int x = 0; x < out->width; x++)                                 \
1583                     dst[x] = xf0[x];                                                 \
1584             }                                                                        \
1585                                                                                      \
1586             dst += out->linesize[p] / div;                                           \
1587             xf1 += b->linesize[p] / div;                                             \
1588         }                                                                            \
1589     }                                                                                \
1590 }
1591 
1592 SQUEEZEH_TRANSITION(8, uint8_t, 1)
1593 SQUEEZEH_TRANSITION(16, uint16_t, 2)
1594 
1595 #define SQUEEZEV_TRANSITION(name, type, div)                                         \
1596 static void squeezev##name##_transition(AVFilterContext *ctx,                        \
1597                                 const AVFrame *a, const AVFrame *b, AVFrame *out,    \
1598                                 float progress,                                      \
1599                                 int slice_start, int slice_end, int jobnr)           \
1600 {                                                                                    \
1601     XFadeContext *s = ctx->priv;                                                     \
1602     const float w = out->width;                                                      \
1603     const int height = slice_end - slice_start;                                      \
1604                                                                                      \
1605     for (int p = 0; p < s->nb_planes; p++) {                                         \
1606         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1607         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1608         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
1609                                                                                      \
1610         for (int y = 0; y < height; y++) {                                           \
1611             for (int x = 0; x < out->width; x++) {                                   \
1612                 const float z = .5f + (x / w - .5f) / progress;                      \
1613                                                                                      \
1614                 if (z < 0.f || z > 1.f) {                                            \
1615                     dst[x] = xf1[x];                                                 \
1616                 } else {                                                             \
1617                     const int xx = lrintf(z * (w - 1.f));                            \
1618                                                                                      \
1619                     dst[x] = xf0[xx];                                                \
1620                 }                                                                    \
1621             }                                                                        \
1622                                                                                      \
1623             dst += out->linesize[p] / div;                                           \
1624             xf0 += a->linesize[p] / div;                                             \
1625             xf1 += b->linesize[p] / div;                                             \
1626         }                                                                            \
1627     }                                                                                \
1628 }
1629 
1630 SQUEEZEV_TRANSITION(8, uint8_t, 1)
1631 SQUEEZEV_TRANSITION(16, uint16_t, 2)
1632 
zoom(float * u,float * v,float amount)1633 static void zoom(float *u, float *v, float amount)
1634 {
1635     *u = 0.5f + ((*u - 0.5f) * amount);
1636     *v = 0.5f + ((*v - 0.5f) * amount);
1637 }
1638 
1639 #define ZOOMIN_TRANSITION(name, type, div)                                           \
1640 static void zoomin##name##_transition(AVFilterContext *ctx,                          \
1641                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1642                             float progress,                                          \
1643                             int slice_start, int slice_end, int jobnr)               \
1644 {                                                                                    \
1645     XFadeContext *s = ctx->priv;                                                     \
1646     const float w = out->width;                                                      \
1647     const float h = out->height;                                                     \
1648     const float zf = smoothstep(0.5f, 1.f, progress);                                \
1649                                                                                      \
1650     for (int p = 0; p < s->nb_planes; p++) {                                         \
1651         const type *xf0 = (const type *)(a->data[p]);                                \
1652         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1653         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
1654                                                                                      \
1655         for (int y = slice_start; y < slice_end; y++) {                              \
1656             for (int x = 0; x < w; x++) {                                            \
1657                 float zv, u, v;                                                      \
1658                 int iu, iv;                                                          \
1659                                                                                      \
1660                 u = x / w;                                                           \
1661                 v = y / h;                                                           \
1662                 zoom(&u, &v, zf);                                                    \
1663                 iu = ceilf(u * (w - 1));                                             \
1664                 iv = ceilf(v * (h - 1));                                             \
1665                 zv = xf0[iu + iv * a->linesize[p] / div];                            \
1666                 dst[x] = mix(zv, xf1[x], smoothstep(0.f, 0.5f, progress));           \
1667             }                                                                        \
1668             dst += out->linesize[p] / div;                                           \
1669             xf1 += b->linesize[p] / div;                                             \
1670         }                                                                            \
1671     }                                                                                \
1672 }
1673 
1674 ZOOMIN_TRANSITION(8, uint8_t, 1)
1675 ZOOMIN_TRANSITION(16, uint16_t, 2)
1676 
1677 #define FADEFAST_TRANSITION(name, type, div)                                         \
1678 static void fadefast##name##_transition(AVFilterContext *ctx,                        \
1679                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1680                             float progress,                                          \
1681                             int slice_start, int slice_end, int jobnr)               \
1682 {                                                                                    \
1683     XFadeContext *s = ctx->priv;                                                     \
1684     const int height = slice_end - slice_start;                                      \
1685     const float imax = 1.f / s->max_value;                                           \
1686                                                                                      \
1687     for (int p = 0; p < s->nb_planes; p++) {                                         \
1688         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1689         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1690         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
1691                                                                                      \
1692         for (int y = 0; y < height; y++) {                                           \
1693             for (int x = 0; x < out->width; x++) {                                   \
1694                 dst[x] = mix(xf0[x], xf1[x], powf(progress, 1.f +                    \
1695                                                   logf(1.f+FFABS(xf0[x]-xf1[x])*imax)\
1696                                                   ));                                \
1697             }                                                                        \
1698                                                                                      \
1699             dst += out->linesize[p] / div;                                           \
1700             xf0 += a->linesize[p] / div;                                             \
1701             xf1 += b->linesize[p] / div;                                             \
1702         }                                                                            \
1703     }                                                                                \
1704 }
1705 
1706 FADEFAST_TRANSITION(8, uint8_t, 1)
1707 FADEFAST_TRANSITION(16, uint16_t, 2)
1708 
1709 #define FADESLOW_TRANSITION(name, type, div)                                         \
1710 static void fadeslow##name##_transition(AVFilterContext *ctx,                        \
1711                             const AVFrame *a, const AVFrame *b, AVFrame *out,        \
1712                             float progress,                                          \
1713                             int slice_start, int slice_end, int jobnr)               \
1714 {                                                                                    \
1715     XFadeContext *s = ctx->priv;                                                     \
1716     const int height = slice_end - slice_start;                                      \
1717     const float imax = 1.f / s->max_value;                                           \
1718                                                                                      \
1719     for (int p = 0; p < s->nb_planes; p++) {                                         \
1720         const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1721         const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1722         type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
1723                                                                                      \
1724         for (int y = 0; y < height; y++) {                                           \
1725             for (int x = 0; x < out->width; x++) {                                   \
1726                 dst[x] = mix(xf0[x], xf1[x], powf(progress, 1.f +                    \
1727                                                   logf(2.f-FFABS(xf0[x]-xf1[x])*imax)\
1728                                                   ));                                \
1729             }                                                                        \
1730                                                                                      \
1731             dst += out->linesize[p] / div;                                           \
1732             xf0 += a->linesize[p] / div;                                             \
1733             xf1 += b->linesize[p] / div;                                             \
1734         }                                                                            \
1735     }                                                                                \
1736 }
1737 
1738 FADESLOW_TRANSITION(8, uint8_t, 1)
1739 FADESLOW_TRANSITION(16, uint16_t, 2)
1740 
getpix(void * priv,double x,double y,int plane,int nb)1741 static inline double getpix(void *priv, double x, double y, int plane, int nb)
1742 {
1743     XFadeContext *s = priv;
1744     AVFrame *in = s->xf[nb];
1745     const uint8_t *src = in->data[FFMIN(plane, s->nb_planes - 1)];
1746     int linesize = in->linesize[FFMIN(plane, s->nb_planes - 1)];
1747     const int w = in->width;
1748     const int h = in->height;
1749 
1750     int xi, yi;
1751 
1752     xi = av_clipd(x, 0, w - 1);
1753     yi = av_clipd(y, 0, h - 1);
1754 
1755     if (s->depth > 8) {
1756         const uint16_t *src16 = (const uint16_t*)src;
1757 
1758         linesize /= 2;
1759         return src16[xi + yi * linesize];
1760     } else {
1761         return src[xi + yi * linesize];
1762     }
1763 }
1764 
a0(void * priv,double x,double y)1765 static double a0(void *priv, double x, double y) { return getpix(priv, x, y, 0, 0); }
a1(void * priv,double x,double y)1766 static double a1(void *priv, double x, double y) { return getpix(priv, x, y, 1, 0); }
a2(void * priv,double x,double y)1767 static double a2(void *priv, double x, double y) { return getpix(priv, x, y, 2, 0); }
a3(void * priv,double x,double y)1768 static double a3(void *priv, double x, double y) { return getpix(priv, x, y, 3, 0); }
1769 
b0(void * priv,double x,double y)1770 static double b0(void *priv, double x, double y) { return getpix(priv, x, y, 0, 1); }
b1(void * priv,double x,double y)1771 static double b1(void *priv, double x, double y) { return getpix(priv, x, y, 1, 1); }
b2(void * priv,double x,double y)1772 static double b2(void *priv, double x, double y) { return getpix(priv, x, y, 2, 1); }
b3(void * priv,double x,double y)1773 static double b3(void *priv, double x, double y) { return getpix(priv, x, y, 3, 1); }
1774 
config_output(AVFilterLink * outlink)1775 static int config_output(AVFilterLink *outlink)
1776 {
1777     AVFilterContext *ctx = outlink->src;
1778     AVFilterLink *inlink0 = ctx->inputs[0];
1779     AVFilterLink *inlink1 = ctx->inputs[1];
1780     XFadeContext *s = ctx->priv;
1781     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink0->format);
1782 
1783     if (inlink0->w != inlink1->w || inlink0->h != inlink1->h) {
1784         av_log(ctx, AV_LOG_ERROR, "First input link %s parameters "
1785                "(size %dx%d) do not match the corresponding "
1786                "second input link %s parameters (size %dx%d)\n",
1787                ctx->input_pads[0].name, inlink0->w, inlink0->h,
1788                ctx->input_pads[1].name, inlink1->w, inlink1->h);
1789         return AVERROR(EINVAL);
1790     }
1791 
1792     if (inlink0->time_base.num != inlink1->time_base.num ||
1793         inlink0->time_base.den != inlink1->time_base.den) {
1794         av_log(ctx, AV_LOG_ERROR, "First input link %s timebase "
1795                "(%d/%d) do not match the corresponding "
1796                "second input link %s timebase (%d/%d)\n",
1797                ctx->input_pads[0].name, inlink0->time_base.num, inlink0->time_base.den,
1798                ctx->input_pads[1].name, inlink1->time_base.num, inlink1->time_base.den);
1799         return AVERROR(EINVAL);
1800     }
1801 
1802     if (!inlink0->frame_rate.num || !inlink0->frame_rate.den) {
1803         av_log(ctx, AV_LOG_ERROR, "The inputs needs to be a constant frame rate; "
1804                "current rate of %d/%d is invalid\n", inlink0->frame_rate.num, inlink0->frame_rate.den);
1805         return AVERROR(EINVAL);
1806     }
1807 
1808     if (inlink0->frame_rate.num != inlink1->frame_rate.num ||
1809         inlink0->frame_rate.den != inlink1->frame_rate.den) {
1810         av_log(ctx, AV_LOG_ERROR, "First input link %s frame rate "
1811                "(%d/%d) do not match the corresponding "
1812                "second input link %s frame rate (%d/%d)\n",
1813                ctx->input_pads[0].name, inlink0->frame_rate.num, inlink0->frame_rate.den,
1814                ctx->input_pads[1].name, inlink1->frame_rate.num, inlink1->frame_rate.den);
1815         return AVERROR(EINVAL);
1816     }
1817 
1818     outlink->w = inlink0->w;
1819     outlink->h = inlink0->h;
1820     outlink->time_base = inlink0->time_base;
1821     outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
1822     outlink->frame_rate = inlink0->frame_rate;
1823 
1824     s->depth = pix_desc->comp[0].depth;
1825     s->is_rgb = !!(pix_desc->flags & AV_PIX_FMT_FLAG_RGB);
1826     s->nb_planes = av_pix_fmt_count_planes(inlink0->format);
1827     s->max_value = (1 << s->depth) - 1;
1828     s->black[0] = 0;
1829     s->black[1] = s->black[2] = s->is_rgb ? 0 : s->max_value / 2;
1830     s->black[3] = s->max_value;
1831     s->white[0] = s->white[3] = s->max_value;
1832     s->white[1] = s->white[2] = s->is_rgb ? s->max_value : s->max_value / 2;
1833 
1834     s->first_pts = s->last_pts = s->pts = AV_NOPTS_VALUE;
1835 
1836     if (s->duration)
1837         s->duration_pts = av_rescale_q(s->duration, AV_TIME_BASE_Q, outlink->time_base);
1838     if (s->offset)
1839         s->offset_pts = av_rescale_q(s->offset, AV_TIME_BASE_Q, outlink->time_base);
1840 
1841     switch (s->transition) {
1842     case CUSTOM:     s->transitionf = s->depth <= 8 ? custom8_transition     : custom16_transition;     break;
1843     case FADE:       s->transitionf = s->depth <= 8 ? fade8_transition       : fade16_transition;       break;
1844     case WIPELEFT:   s->transitionf = s->depth <= 8 ? wipeleft8_transition   : wipeleft16_transition;   break;
1845     case WIPERIGHT:  s->transitionf = s->depth <= 8 ? wiperight8_transition  : wiperight16_transition;  break;
1846     case WIPEUP:     s->transitionf = s->depth <= 8 ? wipeup8_transition     : wipeup16_transition;     break;
1847     case WIPEDOWN:   s->transitionf = s->depth <= 8 ? wipedown8_transition   : wipedown16_transition;   break;
1848     case SLIDELEFT:  s->transitionf = s->depth <= 8 ? slideleft8_transition  : slideleft16_transition;  break;
1849     case SLIDERIGHT: s->transitionf = s->depth <= 8 ? slideright8_transition : slideright16_transition; break;
1850     case SLIDEUP:    s->transitionf = s->depth <= 8 ? slideup8_transition    : slideup16_transition;    break;
1851     case SLIDEDOWN:  s->transitionf = s->depth <= 8 ? slidedown8_transition  : slidedown16_transition;  break;
1852     case CIRCLECROP: s->transitionf = s->depth <= 8 ? circlecrop8_transition : circlecrop16_transition; break;
1853     case RECTCROP:   s->transitionf = s->depth <= 8 ? rectcrop8_transition   : rectcrop16_transition;   break;
1854     case DISTANCE:   s->transitionf = s->depth <= 8 ? distance8_transition   : distance16_transition;   break;
1855     case FADEBLACK:  s->transitionf = s->depth <= 8 ? fadeblack8_transition  : fadeblack16_transition;  break;
1856     case FADEWHITE:  s->transitionf = s->depth <= 8 ? fadewhite8_transition  : fadewhite16_transition;  break;
1857     case RADIAL:     s->transitionf = s->depth <= 8 ? radial8_transition     : radial16_transition;     break;
1858     case SMOOTHLEFT: s->transitionf = s->depth <= 8 ? smoothleft8_transition : smoothleft16_transition; break;
1859     case SMOOTHRIGHT:s->transitionf = s->depth <= 8 ? smoothright8_transition: smoothright16_transition;break;
1860     case SMOOTHUP:   s->transitionf = s->depth <= 8 ? smoothup8_transition   : smoothup16_transition;   break;
1861     case SMOOTHDOWN: s->transitionf = s->depth <= 8 ? smoothdown8_transition : smoothdown16_transition; break;
1862     case CIRCLEOPEN: s->transitionf = s->depth <= 8 ? circleopen8_transition : circleopen16_transition; break;
1863     case CIRCLECLOSE:s->transitionf = s->depth <= 8 ? circleclose8_transition: circleclose16_transition;break;
1864     case VERTOPEN:   s->transitionf = s->depth <= 8 ? vertopen8_transition   : vertopen16_transition;   break;
1865     case VERTCLOSE:  s->transitionf = s->depth <= 8 ? vertclose8_transition  : vertclose16_transition;  break;
1866     case HORZOPEN:   s->transitionf = s->depth <= 8 ? horzopen8_transition   : horzopen16_transition;   break;
1867     case HORZCLOSE:  s->transitionf = s->depth <= 8 ? horzclose8_transition  : horzclose16_transition;  break;
1868     case DISSOLVE:   s->transitionf = s->depth <= 8 ? dissolve8_transition   : dissolve16_transition;   break;
1869     case PIXELIZE:   s->transitionf = s->depth <= 8 ? pixelize8_transition   : pixelize16_transition;   break;
1870     case DIAGTL:     s->transitionf = s->depth <= 8 ? diagtl8_transition     : diagtl16_transition;     break;
1871     case DIAGTR:     s->transitionf = s->depth <= 8 ? diagtr8_transition     : diagtr16_transition;     break;
1872     case DIAGBL:     s->transitionf = s->depth <= 8 ? diagbl8_transition     : diagbl16_transition;     break;
1873     case DIAGBR:     s->transitionf = s->depth <= 8 ? diagbr8_transition     : diagbr16_transition;     break;
1874     case HLSLICE:    s->transitionf = s->depth <= 8 ? hlslice8_transition    : hlslice16_transition;    break;
1875     case HRSLICE:    s->transitionf = s->depth <= 8 ? hrslice8_transition    : hrslice16_transition;    break;
1876     case VUSLICE:    s->transitionf = s->depth <= 8 ? vuslice8_transition    : vuslice16_transition;    break;
1877     case VDSLICE:    s->transitionf = s->depth <= 8 ? vdslice8_transition    : vdslice16_transition;    break;
1878     case HBLUR:      s->transitionf = s->depth <= 8 ? hblur8_transition      : hblur16_transition;      break;
1879     case FADEGRAYS:  s->transitionf = s->depth <= 8 ? fadegrays8_transition  : fadegrays16_transition;  break;
1880     case WIPETL:     s->transitionf = s->depth <= 8 ? wipetl8_transition     : wipetl16_transition;     break;
1881     case WIPETR:     s->transitionf = s->depth <= 8 ? wipetr8_transition     : wipetr16_transition;     break;
1882     case WIPEBL:     s->transitionf = s->depth <= 8 ? wipebl8_transition     : wipebl16_transition;     break;
1883     case WIPEBR:     s->transitionf = s->depth <= 8 ? wipebr8_transition     : wipebr16_transition;     break;
1884     case SQUEEZEH:   s->transitionf = s->depth <= 8 ? squeezeh8_transition   : squeezeh16_transition;   break;
1885     case SQUEEZEV:   s->transitionf = s->depth <= 8 ? squeezev8_transition   : squeezev16_transition;   break;
1886     case ZOOMIN:     s->transitionf = s->depth <= 8 ? zoomin8_transition     : zoomin16_transition;     break;
1887     case FADEFAST:   s->transitionf = s->depth <= 8 ? fadefast8_transition   : fadefast16_transition;   break;
1888     case FADESLOW:   s->transitionf = s->depth <= 8 ? fadeslow8_transition   : fadeslow16_transition;   break;
1889     default: return AVERROR_BUG;
1890     }
1891 
1892     if (s->transition == CUSTOM) {
1893         static const char *const func2_names[]    = {
1894             "a0", "a1", "a2", "a3",
1895             "b0", "b1", "b2", "b3",
1896             NULL
1897         };
1898         double (*func2[])(void *, double, double) = {
1899             a0, a1, a2, a3,
1900             b0, b1, b2, b3,
1901             NULL };
1902         int ret;
1903 
1904         if (!s->custom_str)
1905             return AVERROR(EINVAL);
1906         ret = av_expr_parse(&s->e, s->custom_str, var_names,
1907                             NULL, NULL, func2_names, func2, 0, ctx);
1908         if (ret < 0)
1909             return ret;
1910     }
1911 
1912     return 0;
1913 }
1914 
xfade_slice(AVFilterContext * ctx,void * arg,int jobnr,int nb_jobs)1915 static int xfade_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
1916 {
1917     XFadeContext *s = ctx->priv;
1918     AVFilterLink *outlink = ctx->outputs[0];
1919     ThreadData *td = arg;
1920     int slice_start = (outlink->h *  jobnr   ) / nb_jobs;
1921     int slice_end   = (outlink->h * (jobnr+1)) / nb_jobs;
1922 
1923     s->transitionf(ctx, td->xf[0], td->xf[1], td->out, td->progress, slice_start, slice_end, jobnr);
1924 
1925     return 0;
1926 }
1927 
xfade_frame(AVFilterContext * ctx,AVFrame * a,AVFrame * b)1928 static int xfade_frame(AVFilterContext *ctx, AVFrame *a, AVFrame *b)
1929 {
1930     XFadeContext *s = ctx->priv;
1931     AVFilterLink *outlink = ctx->outputs[0];
1932     float progress = av_clipf(1.f - ((float)(s->pts - s->first_pts - s->offset_pts) / s->duration_pts), 0.f, 1.f);
1933     ThreadData td;
1934     AVFrame *out;
1935 
1936     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1937     if (!out)
1938         return AVERROR(ENOMEM);
1939     av_frame_copy_props(out, a);
1940 
1941     td.xf[0] = a, td.xf[1] = b, td.out = out, td.progress = progress;
1942     ff_filter_execute(ctx, xfade_slice, &td, NULL,
1943                       FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
1944 
1945     out->pts = s->pts;
1946 
1947     return ff_filter_frame(outlink, out);
1948 }
1949 
xfade_activate(AVFilterContext * ctx)1950 static int xfade_activate(AVFilterContext *ctx)
1951 {
1952     XFadeContext *s = ctx->priv;
1953     AVFilterLink *outlink = ctx->outputs[0];
1954     AVFrame *in = NULL;
1955     int ret = 0, status;
1956     int64_t pts;
1957 
1958     FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
1959 
1960     if (s->xfade_is_over) {
1961         if (!s->eof[0]) {
1962             ret = ff_inlink_consume_frame(ctx->inputs[0], &in);
1963             if (ret > 0)
1964                 av_frame_free(&in);
1965         }
1966         ret = ff_inlink_consume_frame(ctx->inputs[1], &in);
1967         if (ret < 0) {
1968             return ret;
1969         } else if (ret > 0) {
1970             in->pts = (in->pts - s->last_pts) + s->pts;
1971             return ff_filter_frame(outlink, in);
1972         } else if (ff_inlink_acknowledge_status(ctx->inputs[1], &status, &pts)) {
1973             ff_outlink_set_status(outlink, status, s->pts);
1974             return 0;
1975         } else if (!ret) {
1976             if (ff_outlink_frame_wanted(outlink))
1977                 ff_inlink_request_frame(ctx->inputs[1]);
1978             return 0;
1979         }
1980     }
1981 
1982     if (ff_inlink_queued_frames(ctx->inputs[0]) > 0) {
1983         s->xf[0] = ff_inlink_peek_frame(ctx->inputs[0], 0);
1984         if (s->xf[0]) {
1985             if (s->first_pts == AV_NOPTS_VALUE) {
1986                 s->first_pts = s->xf[0]->pts;
1987             }
1988             s->pts = s->xf[0]->pts;
1989             if (s->first_pts + s->offset_pts > s->xf[0]->pts) {
1990                 s->xf[0] = NULL;
1991                 s->need_second = 0;
1992                 ff_inlink_consume_frame(ctx->inputs[0], &in);
1993                 return ff_filter_frame(outlink, in);
1994             }
1995 
1996             s->need_second = 1;
1997         }
1998     }
1999 
2000     if (s->xf[0] && ff_inlink_queued_frames(ctx->inputs[1]) > 0) {
2001         ff_inlink_consume_frame(ctx->inputs[0], &s->xf[0]);
2002         ff_inlink_consume_frame(ctx->inputs[1], &s->xf[1]);
2003 
2004         s->last_pts = s->xf[1]->pts;
2005         s->pts = s->xf[0]->pts;
2006         if (s->xf[0]->pts - (s->first_pts + s->offset_pts) > s->duration_pts)
2007             s->xfade_is_over = 1;
2008         ret = xfade_frame(ctx, s->xf[0], s->xf[1]);
2009         av_frame_free(&s->xf[0]);
2010         av_frame_free(&s->xf[1]);
2011         return ret;
2012     }
2013 
2014     if (ff_inlink_queued_frames(ctx->inputs[0]) > 0 &&
2015         ff_inlink_queued_frames(ctx->inputs[1]) > 0) {
2016         ff_filter_set_ready(ctx, 100);
2017         return 0;
2018     }
2019 
2020     if (ff_outlink_frame_wanted(outlink)) {
2021         if (!s->eof[0] && ff_outlink_get_status(ctx->inputs[0])) {
2022             s->eof[0] = 1;
2023             s->xfade_is_over = 1;
2024         }
2025         if (!s->eof[1] && ff_outlink_get_status(ctx->inputs[1])) {
2026             s->eof[1] = 1;
2027         }
2028         if (!s->eof[0] && !s->xf[0] && ff_inlink_queued_frames(ctx->inputs[0]) == 0)
2029             ff_inlink_request_frame(ctx->inputs[0]);
2030         if (!s->eof[1] && (s->need_second || s->eof[0]) && ff_inlink_queued_frames(ctx->inputs[1]) == 0)
2031             ff_inlink_request_frame(ctx->inputs[1]);
2032         if (s->eof[0] && s->eof[1] && (
2033             ff_inlink_queued_frames(ctx->inputs[0]) <= 0 &&
2034             ff_inlink_queued_frames(ctx->inputs[1]) <= 0)) {
2035             ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE);
2036         } else if (s->xfade_is_over) {
2037             ff_filter_set_ready(ctx, 100);
2038         }
2039         return 0;
2040     }
2041 
2042     return FFERROR_NOT_READY;
2043 }
2044 
2045 static const AVFilterPad xfade_inputs[] = {
2046     {
2047         .name          = "main",
2048         .type          = AVMEDIA_TYPE_VIDEO,
2049     },
2050     {
2051         .name          = "xfade",
2052         .type          = AVMEDIA_TYPE_VIDEO,
2053     },
2054 };
2055 
2056 static const AVFilterPad xfade_outputs[] = {
2057     {
2058         .name          = "default",
2059         .type          = AVMEDIA_TYPE_VIDEO,
2060         .config_props  = config_output,
2061     },
2062 };
2063 
2064 const AVFilter ff_vf_xfade = {
2065     .name          = "xfade",
2066     .description   = NULL_IF_CONFIG_SMALL("Cross fade one video with another video."),
2067     .priv_size     = sizeof(XFadeContext),
2068     .priv_class    = &xfade_class,
2069     .activate      = xfade_activate,
2070     .uninit        = uninit,
2071     FILTER_INPUTS(xfade_inputs),
2072     FILTER_OUTPUTS(xfade_outputs),
2073     FILTER_PIXFMTS_ARRAY(pix_fmts),
2074     .flags         = AVFILTER_FLAG_SLICE_THREADS,
2075 };
2076