FFmpeg
vf_xfade.c
Go to the documentation of this file.
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 
32  CUSTOM = -1,
70 };
71 
72 typedef struct XFadeContext {
73  const AVClass *class;
74 
76  int64_t duration;
77  int64_t offset;
78  char *custom_str;
79 
80  int nb_planes;
81  int depth;
82 
83  int64_t duration_pts;
84  int64_t offset_pts;
85  int64_t first_pts;
86  int64_t last_pts;
87  int64_t pts;
90  int eof[2];
91  AVFrame *xf[2];
92  int max_value;
93  uint16_t black[4];
94  uint16_t white[4];
95 
96  void (*transitionf)(AVFilterContext *ctx, const AVFrame *a, const AVFrame *b, AVFrame *out, float progress,
97  int slice_start, int slice_end, int jobnr);
98 
100 } XFadeContext;
101 
102 static const char *const var_names[] = { "X", "Y", "W", "H", "A", "B", "PLANE", "P", NULL };
104 
105 typedef struct ThreadData {
106  const AVFrame *xf[2];
107  AVFrame *out;
108  float progress;
109 } ThreadData;
110 
112 {
113  static const enum AVPixelFormat pix_fmts[] = {
130  };
131 
132  AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
133  if (!fmts_list)
134  return AVERROR(ENOMEM);
135  return ff_set_common_formats(ctx, fmts_list);
136 }
137 
139 {
140  XFadeContext *s = ctx->priv;
141 
142  av_expr_free(s->e);
143 }
144 
145 #define OFFSET(x) offsetof(XFadeContext, x)
146 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
147 
148 static const AVOption xfade_options[] = {
149  { "transition", "set cross fade transition", OFFSET(transition), AV_OPT_TYPE_INT, {.i64=FADE}, -1, NB_TRANSITIONS-1, FLAGS, "transition" },
150  { "custom", "custom transition", 0, AV_OPT_TYPE_CONST, {.i64=CUSTOM}, 0, 0, FLAGS, "transition" },
151  { "fade", "fade transition", 0, AV_OPT_TYPE_CONST, {.i64=FADE}, 0, 0, FLAGS, "transition" },
152  { "wipeleft", "wipe left transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPELEFT}, 0, 0, FLAGS, "transition" },
153  { "wiperight", "wipe right transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPERIGHT}, 0, 0, FLAGS, "transition" },
154  { "wipeup", "wipe up transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPEUP}, 0, 0, FLAGS, "transition" },
155  { "wipedown", "wipe down transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPEDOWN}, 0, 0, FLAGS, "transition" },
156  { "slideleft", "slide left transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDELEFT}, 0, 0, FLAGS, "transition" },
157  { "slideright", "slide right transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDERIGHT}, 0, 0, FLAGS, "transition" },
158  { "slideup", "slide up transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDEUP}, 0, 0, FLAGS, "transition" },
159  { "slidedown", "slide down transition", 0, AV_OPT_TYPE_CONST, {.i64=SLIDEDOWN}, 0, 0, FLAGS, "transition" },
160  { "circlecrop", "circle crop transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLECROP}, 0, 0, FLAGS, "transition" },
161  { "rectcrop", "rect crop transition", 0, AV_OPT_TYPE_CONST, {.i64=RECTCROP}, 0, 0, FLAGS, "transition" },
162  { "distance", "distance transition", 0, AV_OPT_TYPE_CONST, {.i64=DISTANCE}, 0, 0, FLAGS, "transition" },
163  { "fadeblack", "fadeblack transition", 0, AV_OPT_TYPE_CONST, {.i64=FADEBLACK}, 0, 0, FLAGS, "transition" },
164  { "fadewhite", "fadewhite transition", 0, AV_OPT_TYPE_CONST, {.i64=FADEWHITE}, 0, 0, FLAGS, "transition" },
165  { "radial", "radial transition", 0, AV_OPT_TYPE_CONST, {.i64=RADIAL}, 0, 0, FLAGS, "transition" },
166  { "smoothleft", "smoothleft transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHLEFT}, 0, 0, FLAGS, "transition" },
167  { "smoothright","smoothright transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHRIGHT},0, 0, FLAGS, "transition" },
168  { "smoothup", "smoothup transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHUP}, 0, 0, FLAGS, "transition" },
169  { "smoothdown", "smoothdown transition", 0, AV_OPT_TYPE_CONST, {.i64=SMOOTHDOWN}, 0, 0, FLAGS, "transition" },
170  { "circleopen", "circleopen transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLEOPEN}, 0, 0, FLAGS, "transition" },
171  { "circleclose","circleclose transition", 0, AV_OPT_TYPE_CONST, {.i64=CIRCLECLOSE},0, 0, FLAGS, "transition" },
172  { "vertopen", "vert open transition", 0, AV_OPT_TYPE_CONST, {.i64=VERTOPEN}, 0, 0, FLAGS, "transition" },
173  { "vertclose", "vert close transition", 0, AV_OPT_TYPE_CONST, {.i64=VERTCLOSE}, 0, 0, FLAGS, "transition" },
174  { "horzopen", "horz open transition", 0, AV_OPT_TYPE_CONST, {.i64=HORZOPEN}, 0, 0, FLAGS, "transition" },
175  { "horzclose", "horz close transition", 0, AV_OPT_TYPE_CONST, {.i64=HORZCLOSE}, 0, 0, FLAGS, "transition" },
176  { "dissolve", "dissolve transition", 0, AV_OPT_TYPE_CONST, {.i64=DISSOLVE}, 0, 0, FLAGS, "transition" },
177  { "pixelize", "pixelize transition", 0, AV_OPT_TYPE_CONST, {.i64=PIXELIZE}, 0, 0, FLAGS, "transition" },
178  { "diagtl", "diag tl transition", 0, AV_OPT_TYPE_CONST, {.i64=DIAGTL}, 0, 0, FLAGS, "transition" },
179  { "diagtr", "diag tr transition", 0, AV_OPT_TYPE_CONST, {.i64=DIAGTR}, 0, 0, FLAGS, "transition" },
180  { "diagbl", "diag bl transition", 0, AV_OPT_TYPE_CONST, {.i64=DIAGBL}, 0, 0, FLAGS, "transition" },
181  { "diagbr", "diag br transition", 0, AV_OPT_TYPE_CONST, {.i64=DIAGBR}, 0, 0, FLAGS, "transition" },
182  { "hlslice", "hl slice transition", 0, AV_OPT_TYPE_CONST, {.i64=HLSLICE}, 0, 0, FLAGS, "transition" },
183  { "hrslice", "hr slice transition", 0, AV_OPT_TYPE_CONST, {.i64=HRSLICE}, 0, 0, FLAGS, "transition" },
184  { "vuslice", "vu slice transition", 0, AV_OPT_TYPE_CONST, {.i64=VUSLICE}, 0, 0, FLAGS, "transition" },
185  { "vdslice", "vd slice transition", 0, AV_OPT_TYPE_CONST, {.i64=VDSLICE}, 0, 0, FLAGS, "transition" },
186  { "hblur", "hblur transition", 0, AV_OPT_TYPE_CONST, {.i64=HBLUR}, 0, 0, FLAGS, "transition" },
187  { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=1000000}, 0, 60000000, FLAGS },
188  { "offset", "set cross fade start relative to first input stream", OFFSET(offset), AV_OPT_TYPE_DURATION, {.i64=0}, INT64_MIN, INT64_MAX, FLAGS },
189  { "expr", "set expression for custom transition", OFFSET(custom_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
190  { NULL }
191 };
192 
193 AVFILTER_DEFINE_CLASS(xfade);
194 
195 #define CUSTOM_TRANSITION(name, type, div) \
196 static void custom##name##_transition(AVFilterContext *ctx, \
197  const AVFrame *a, const AVFrame *b, AVFrame *out, \
198  float progress, \
199  int slice_start, int slice_end, int jobnr) \
200 { \
201  XFadeContext *s = ctx->priv; \
202  const int height = slice_end - slice_start; \
203  \
204  double values[VAR_VARS_NB]; \
205  values[VAR_W] = out->width; \
206  values[VAR_H] = out->height; \
207  values[VAR_PROGRESS] = progress; \
208  \
209  for (int p = 0; p < s->nb_planes; p++) { \
210  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
211  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
212  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
213  \
214  values[VAR_PLANE] = p; \
215  \
216  for (int y = 0; y < height; y++) { \
217  values[VAR_Y] = slice_start + y; \
218  for (int x = 0; x < out->width; x++) { \
219  values[VAR_X] = x; \
220  values[VAR_A] = xf0[x]; \
221  values[VAR_B] = xf1[x]; \
222  dst[x] = av_expr_eval(s->e, values, s); \
223  } \
224  \
225  dst += out->linesize[p] / div; \
226  xf0 += a->linesize[p] / div; \
227  xf1 += b->linesize[p] / div; \
228  } \
229  } \
230 }
231 
233 CUSTOM_TRANSITION(16, uint16_t, 2)
234 
235 static inline float mix(float a, float b, float mix)
236 {
237  return a * mix + b * (1.f - mix);
238 }
239 
240 static inline float fract(float a)
241 {
242  return a - floorf(a);
243 }
244 
245 static inline float smoothstep(float edge0, float edge1, float x)
246 {
247  float t;
248 
249  t = av_clipf((x - edge0) / (edge1 - edge0), 0.f, 1.f);
250 
251  return t * t * (3.f - 2.f * t);
252 }
253 
254 #define FADE_TRANSITION(name, type, div) \
255 static void fade##name##_transition(AVFilterContext *ctx, \
256  const AVFrame *a, const AVFrame *b, AVFrame *out, \
257  float progress, \
258  int slice_start, int slice_end, int jobnr) \
259 { \
260  XFadeContext *s = ctx->priv; \
261  const int height = slice_end - slice_start; \
262  \
263  for (int p = 0; p < s->nb_planes; p++) { \
264  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
265  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
266  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
267  \
268  for (int y = 0; y < height; y++) { \
269  for (int x = 0; x < out->width; x++) { \
270  dst[x] = mix(xf0[x], xf1[x], progress); \
271  } \
272  \
273  dst += out->linesize[p] / div; \
274  xf0 += a->linesize[p] / div; \
275  xf1 += b->linesize[p] / div; \
276  } \
277  } \
278 }
279 
281 FADE_TRANSITION(16, uint16_t, 2)
282 
283 #define WIPELEFT_TRANSITION(name, type, div) \
284 static void wipeleft##name##_transition(AVFilterContext *ctx, \
285  const AVFrame *a, const AVFrame *b, AVFrame *out, \
286  float progress, \
287  int slice_start, int slice_end, int jobnr) \
288 { \
289  XFadeContext *s = ctx->priv; \
290  const int height = slice_end - slice_start; \
291  const int z = out->width * progress; \
292  \
293  for (int p = 0; p < s->nb_planes; p++) { \
294  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
295  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
296  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
297  \
298  for (int y = 0; y < height; y++) { \
299  for (int x = 0; x < out->width; x++) { \
300  dst[x] = x > z ? xf1[x] : xf0[x]; \
301  } \
302  \
303  dst += out->linesize[p] / div; \
304  xf0 += a->linesize[p] / div; \
305  xf1 += b->linesize[p] / div; \
306  } \
307  } \
308 }
309 
311 WIPELEFT_TRANSITION(16, uint16_t, 2)
312 
313 #define WIPERIGHT_TRANSITION(name, type, div) \
314 static void wiperight##name##_transition(AVFilterContext *ctx, \
315  const AVFrame *a, const AVFrame *b, AVFrame *out, \
316  float progress, \
317  int slice_start, int slice_end, int jobnr) \
318 { \
319  XFadeContext *s = ctx->priv; \
320  const int height = slice_end - slice_start; \
321  const int z = out->width * (1.f - progress); \
322  \
323  for (int p = 0; p < s->nb_planes; p++) { \
324  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
325  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
326  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
327  \
328  for (int y = 0; y < height; y++) { \
329  for (int x = 0; x < out->width; x++) { \
330  dst[x] = x > z ? xf0[x] : xf1[x]; \
331  } \
332  \
333  dst += out->linesize[p] / div; \
334  xf0 += a->linesize[p] / div; \
335  xf1 += b->linesize[p] / div; \
336  } \
337  } \
338 }
339 
341 WIPERIGHT_TRANSITION(16, uint16_t, 2)
342 
343 #define WIPEUP_TRANSITION(name, type, div) \
344 static void wipeup##name##_transition(AVFilterContext *ctx, \
345  const AVFrame *a, const AVFrame *b, AVFrame *out, \
346  float progress, \
347  int slice_start, int slice_end, int jobnr) \
348 { \
349  XFadeContext *s = ctx->priv; \
350  const int height = slice_end - slice_start; \
351  const int z = out->height * progress; \
352  \
353  for (int p = 0; p < s->nb_planes; p++) { \
354  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
355  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
356  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
357  \
358  for (int y = 0; y < height; y++) { \
359  for (int x = 0; x < out->width; x++) { \
360  dst[x] = slice_start + y > z ? xf1[x] : xf0[x]; \
361  } \
362  \
363  dst += out->linesize[p] / div; \
364  xf0 += a->linesize[p] / div; \
365  xf1 += b->linesize[p] / div; \
366  } \
367  } \
368 }
369 
371 WIPEUP_TRANSITION(16, uint16_t, 2)
372 
373 #define WIPEDOWN_TRANSITION(name, type, div) \
374 static void wipedown##name##_transition(AVFilterContext *ctx, \
375  const AVFrame *a, const AVFrame *b, AVFrame *out, \
376  float progress, \
377  int slice_start, int slice_end, int jobnr) \
378 { \
379  XFadeContext *s = ctx->priv; \
380  const int height = slice_end - slice_start; \
381  const int z = out->height * (1.f - progress); \
382  \
383  for (int p = 0; p < s->nb_planes; p++) { \
384  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
385  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
386  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
387  \
388  for (int y = 0; y < height; y++) { \
389  for (int x = 0; x < out->width; x++) { \
390  dst[x] = slice_start + y > z ? xf0[x] : xf1[x]; \
391  } \
392  \
393  dst += out->linesize[p] / div; \
394  xf0 += a->linesize[p] / div; \
395  xf1 += b->linesize[p] / div; \
396  } \
397  } \
398 }
399 
401 WIPEDOWN_TRANSITION(16, uint16_t, 2)
402 
403 #define SLIDELEFT_TRANSITION(name, type, div) \
404 static void slideleft##name##_transition(AVFilterContext *ctx, \
405  const AVFrame *a, const AVFrame *b, AVFrame *out, \
406  float progress, \
407  int slice_start, int slice_end, int jobnr) \
408 { \
409  XFadeContext *s = ctx->priv; \
410  const int height = slice_end - slice_start; \
411  const int width = out->width; \
412  const int z = -progress * width; \
413  \
414  for (int p = 0; p < s->nb_planes; p++) { \
415  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
416  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
417  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
418  \
419  for (int y = 0; y < height; y++) { \
420  for (int x = 0; x < width; x++) { \
421  const int zx = z + x; \
422  const int zz = zx % width + width * (zx < 0); \
423  dst[x] = (zx > 0) && (zx < width) ? xf1[zz] : xf0[zz]; \
424  } \
425  \
426  dst += out->linesize[p] / div; \
427  xf0 += a->linesize[p] / div; \
428  xf1 += b->linesize[p] / div; \
429  } \
430  } \
431 }
432 
434 SLIDELEFT_TRANSITION(16, uint16_t, 2)
435 
436 #define SLIDERIGHT_TRANSITION(name, type, div) \
437 static void slideright##name##_transition(AVFilterContext *ctx, \
438  const AVFrame *a, const AVFrame *b, AVFrame *out, \
439  float progress, \
440  int slice_start, int slice_end, int jobnr) \
441 { \
442  XFadeContext *s = ctx->priv; \
443  const int height = slice_end - slice_start; \
444  const int width = out->width; \
445  const int z = progress * width; \
446  \
447  for (int p = 0; p < s->nb_planes; p++) { \
448  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
449  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
450  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
451  \
452  for (int y = 0; y < height; y++) { \
453  for (int x = 0; x < out->width; x++) { \
454  const int zx = z + x; \
455  const int zz = zx % width + width * (zx < 0); \
456  dst[x] = (zx > 0) && (zx < width) ? xf1[zz] : xf0[zz]; \
457  } \
458  \
459  dst += out->linesize[p] / div; \
460  xf0 += a->linesize[p] / div; \
461  xf1 += b->linesize[p] / div; \
462  } \
463  } \
464 }
465 
467 SLIDERIGHT_TRANSITION(16, uint16_t, 2)
468 
469 #define SLIDEUP_TRANSITION(name, type, div) \
470 static void slideup##name##_transition(AVFilterContext *ctx, \
471  const AVFrame *a, const AVFrame *b, AVFrame *out, \
472  float progress, \
473  int slice_start, int slice_end, int jobnr) \
474 { \
475  XFadeContext *s = ctx->priv; \
476  const int height = out->height; \
477  const int z = -progress * height; \
478  \
479  for (int p = 0; p < s->nb_planes; p++) { \
480  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
481  \
482  for (int y = slice_start; y < slice_end; y++) { \
483  const int zy = z + y; \
484  const int zz = zy % height + height * (zy < 0); \
485  const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
486  const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \
487  \
488  for (int x = 0; x < out->width; x++) { \
489  dst[x] = (zy > 0) && (zy < height) ? xf1[x] : xf0[x]; \
490  } \
491  \
492  dst += out->linesize[p] / div; \
493  } \
494  } \
495 }
496 
498 SLIDEUP_TRANSITION(16, uint16_t, 2)
499 
500 #define SLIDEDOWN_TRANSITION(name, type, div) \
501 static void slidedown##name##_transition(AVFilterContext *ctx, \
502  const AVFrame *a, const AVFrame *b, AVFrame *out, \
503  float progress, \
504  int slice_start, int slice_end, int jobnr) \
505 { \
506  XFadeContext *s = ctx->priv; \
507  const int height = out->height; \
508  const int z = progress * height; \
509  \
510  for (int p = 0; p < s->nb_planes; p++) { \
511  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
512  \
513  for (int y = slice_start; y < slice_end; y++) { \
514  const int zy = z + y; \
515  const int zz = zy % height + height * (zy < 0); \
516  const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
517  const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \
518  \
519  for (int x = 0; x < out->width; x++) { \
520  dst[x] = (zy > 0) && (zy < height) ? xf1[x] : xf0[x]; \
521  } \
522  \
523  dst += out->linesize[p] / div; \
524  } \
525  } \
526 }
527 
529 SLIDEDOWN_TRANSITION(16, uint16_t, 2)
530 
531 #define CIRCLECROP_TRANSITION(name, type, div) \
532 static void circlecrop##name##_transition(AVFilterContext *ctx, \
533  const AVFrame *a, const AVFrame *b, AVFrame *out, \
534  float progress, \
535  int slice_start, int slice_end, int jobnr) \
536 { \
537  XFadeContext *s = ctx->priv; \
538  const int width = out->width; \
539  const int height = out->height; \
540  float z = powf(2.f * fabsf(progress - 0.5f), 3.f) * hypotf(width/2, height/2); \
541  \
542  for (int p = 0; p < s->nb_planes; p++) { \
543  const int bg = s->black[p]; \
544  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
545  \
546  for (int y = slice_start; y < slice_end; y++) { \
547  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
548  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
549  \
550  for (int x = 0; x < width; x++) { \
551  float dist = hypotf(x - width / 2, y - height / 2); \
552  int val = progress < 0.5f ? xf1[x] : xf0[x]; \
553  dst[x] = (z < dist) ? bg : val; \
554  } \
555  \
556  dst += out->linesize[p] / div; \
557  } \
558  } \
559 }
560 
562 CIRCLECROP_TRANSITION(16, uint16_t, 2)
563 
564 #define RECTCROP_TRANSITION(name, type, div) \
565 static void rectcrop##name##_transition(AVFilterContext *ctx, \
566  const AVFrame *a, const AVFrame *b, AVFrame *out, \
567  float progress, \
568  int slice_start, int slice_end, int jobnr) \
569 { \
570  XFadeContext *s = ctx->priv; \
571  const int width = out->width; \
572  const int height = out->height; \
573  int zh = fabsf(progress - 0.5f) * height; \
574  int zw = fabsf(progress - 0.5f) * width; \
575  \
576  for (int p = 0; p < s->nb_planes; p++) { \
577  const int bg = s->black[p]; \
578  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
579  \
580  for (int y = slice_start; y < slice_end; y++) { \
581  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
582  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
583  \
584  for (int x = 0; x < width; x++) { \
585  int dist = FFABS(x - width / 2) < zw && \
586  FFABS(y - height / 2) < zh; \
587  int val = progress < 0.5f ? xf1[x] : xf0[x]; \
588  dst[x] = !dist ? bg : val; \
589  } \
590  \
591  dst += out->linesize[p] / div; \
592  } \
593  } \
594 }
595 
597 RECTCROP_TRANSITION(16, uint16_t, 2)
598 
599 #define DISTANCE_TRANSITION(name, type, div) \
600 static void distance##name##_transition(AVFilterContext *ctx, \
601  const AVFrame *a, const AVFrame *b, AVFrame *out, \
602  float progress, \
603  int slice_start, int slice_end, int jobnr) \
604 { \
605  XFadeContext *s = ctx->priv; \
606  const int width = out->width; \
607  const float max = s->max_value; \
608  \
609  for (int y = slice_start; y < slice_end; y++) { \
610  for (int x = 0; x < width; x++) { \
611  float dist = 0.f; \
612  for (int p = 0; p < s->nb_planes; p++) { \
613  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
614  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
615  \
616  dist += (xf0[x] / max - xf1[x] / max) * \
617  (xf0[x] / max - xf1[x] / max); \
618  } \
619  \
620  dist = sqrtf(dist) <= progress; \
621  for (int p = 0; p < s->nb_planes; p++) { \
622  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
623  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
624  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
625  dst[x] = mix(mix(xf0[x], xf1[x], dist), xf1[x], progress); \
626  } \
627  } \
628  } \
629 }
630 
632 DISTANCE_TRANSITION(16, uint16_t, 2)
633 
634 #define FADEBLACK_TRANSITION(name, type, div) \
635 static void fadeblack##name##_transition(AVFilterContext *ctx, \
636  const AVFrame *a, const AVFrame *b, AVFrame *out, \
637  float progress, \
638  int slice_start, int slice_end, int jobnr) \
639 { \
640  XFadeContext *s = ctx->priv; \
641  const int height = slice_end - slice_start; \
642  const float phase = 0.2f; \
643  \
644  for (int p = 0; p < s->nb_planes; p++) { \
645  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
646  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
647  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
648  const int bg = s->black[p]; \
649  \
650  for (int y = 0; y < height; y++) { \
651  for (int x = 0; x < out->width; x++) { \
652  dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)), \
653  mix(bg, xf1[x], smoothstep(phase, 1.f, progress)), \
654  progress); \
655  } \
656  \
657  dst += out->linesize[p] / div; \
658  xf0 += a->linesize[p] / div; \
659  xf1 += b->linesize[p] / div; \
660  } \
661  } \
662 }
663 
665 FADEBLACK_TRANSITION(16, uint16_t, 2)
666 
667 #define FADEWHITE_TRANSITION(name, type, div) \
668 static void fadewhite##name##_transition(AVFilterContext *ctx, \
669  const AVFrame *a, const AVFrame *b, AVFrame *out, \
670  float progress, \
671  int slice_start, int slice_end, int jobnr) \
672 { \
673  XFadeContext *s = ctx->priv; \
674  const int height = slice_end - slice_start; \
675  const float phase = 0.2f; \
676  \
677  for (int p = 0; p < s->nb_planes; p++) { \
678  const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
679  const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
680  type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
681  const int bg = s->white[p]; \
682  \
683  for (int y = 0; y < height; y++) { \
684  for (int x = 0; x < out->width; x++) { \
685  dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)), \
686  mix(bg, xf1[x], smoothstep(phase, 1.f, progress)), \
687  progress); \
688  } \
689  \
690  dst += out->linesize[p] / div; \
691  xf0 += a->linesize[p] / div; \
692  xf1 += b->linesize[p] / div; \
693  } \
694  } \
695 }
696 
698 FADEWHITE_TRANSITION(16, uint16_t, 2)
699 
700 #define RADIAL_TRANSITION(name, type, div) \
701 static void radial##name##_transition(AVFilterContext *ctx, \
702  const AVFrame *a, const AVFrame *b, AVFrame *out, \
703  float progress, \
704  int slice_start, int slice_end, int jobnr) \
705 { \
706  XFadeContext *s = ctx->priv; \
707  const int width = out->width; \
708  const int height = out->height; \
709  \
710  for (int y = slice_start; y < slice_end; y++) { \
711  for (int x = 0; x < width; x++) { \
712  const float smooth = atan2f(x - width / 2, y - height / 2) - \
713  (progress - 0.5f) * (M_PI * 2.5f); \
714  for (int p = 0; p < s->nb_planes; p++) { \
715  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
716  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
717  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
718  \
719  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
720  } \
721  } \
722  } \
723 }
724 
726 RADIAL_TRANSITION(16, uint16_t, 2)
727 
728 #define SMOOTHLEFT_TRANSITION(name, type, div) \
729 static void smoothleft##name##_transition(AVFilterContext *ctx, \
730  const AVFrame *a, const AVFrame *b, AVFrame *out, \
731  float progress, \
732  int slice_start, int slice_end, int jobnr) \
733 { \
734  XFadeContext *s = ctx->priv; \
735  const int width = out->width; \
736  const float w = width; \
737  \
738  for (int y = slice_start; y < slice_end; y++) { \
739  for (int x = 0; x < width; x++) { \
740  const float smooth = 1.f + x / w - progress * 2.f; \
741  \
742  for (int p = 0; p < s->nb_planes; p++) { \
743  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
744  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
745  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
746  \
747  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
748  } \
749  } \
750  } \
751 }
752 
754 SMOOTHLEFT_TRANSITION(16, uint16_t, 2)
755 
756 #define SMOOTHRIGHT_TRANSITION(name, type, div) \
757 static void smoothright##name##_transition(AVFilterContext *ctx, \
758  const AVFrame *a, const AVFrame *b, AVFrame *out, \
759  float progress, \
760  int slice_start, int slice_end, int jobnr) \
761 { \
762  XFadeContext *s = ctx->priv; \
763  const int width = out->width; \
764  const float w = width; \
765  \
766  for (int y = slice_start; y < slice_end; y++) { \
767  for (int x = 0; x < width; x++) { \
768  const float smooth = 1.f + (w - 1 - x) / w - progress * 2.f; \
769  \
770  for (int p = 0; p < s->nb_planes; p++) { \
771  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
772  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
773  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
774  \
775  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
776  } \
777  } \
778  } \
779 }
780 
782 SMOOTHRIGHT_TRANSITION(16, uint16_t, 2)
783 
784 #define SMOOTHUP_TRANSITION(name, type, div) \
785 static void smoothup##name##_transition(AVFilterContext *ctx, \
786  const AVFrame *a, const AVFrame *b, AVFrame *out, \
787  float progress, \
788  int slice_start, int slice_end, int jobnr) \
789 { \
790  XFadeContext *s = ctx->priv; \
791  const int width = out->width; \
792  const float h = out->height; \
793  \
794  for (int y = slice_start; y < slice_end; y++) { \
795  const float smooth = 1.f + y / h - progress * 2.f; \
796  for (int x = 0; x < width; x++) { \
797  for (int p = 0; p < s->nb_planes; p++) { \
798  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
799  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
800  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
801  \
802  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
803  } \
804  } \
805  } \
806 }
807 
809 SMOOTHUP_TRANSITION(16, uint16_t, 2)
810 
811 #define SMOOTHDOWN_TRANSITION(name, type, div) \
812 static void smoothdown##name##_transition(AVFilterContext *ctx, \
813  const AVFrame *a, const AVFrame *b, AVFrame *out, \
814  float progress, \
815  int slice_start, int slice_end, int jobnr) \
816 { \
817  XFadeContext *s = ctx->priv; \
818  const int width = out->width; \
819  const float h = out->height; \
820  \
821  for (int y = slice_start; y < slice_end; y++) { \
822  const float smooth = 1.f + (h - 1 - y) / h - progress * 2.f; \
823  for (int x = 0; x < width; x++) { \
824  for (int p = 0; p < s->nb_planes; p++) { \
825  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
826  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
827  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
828  \
829  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
830  } \
831  } \
832  } \
833 }
834 
836 SMOOTHDOWN_TRANSITION(16, uint16_t, 2)
837 
838 #define CIRCLEOPEN_TRANSITION(name, type, div) \
839 static void circleopen##name##_transition(AVFilterContext *ctx, \
840  const AVFrame *a, const AVFrame *b, AVFrame *out, \
841  float progress, \
842  int slice_start, int slice_end, int jobnr) \
843 { \
844  XFadeContext *s = ctx->priv; \
845  const int width = out->width; \
846  const int height = out->height; \
847  const float z = hypotf(width / 2, height / 2); \
848  const float p = (progress - 0.5f) * 3.f; \
849  \
850  for (int y = slice_start; y < slice_end; y++) { \
851  for (int x = 0; x < width; x++) { \
852  const float smooth = hypotf(x - width / 2, y - height / 2) / z + p; \
853  for (int p = 0; p < s->nb_planes; p++) { \
854  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
855  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
856  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
857  \
858  dst[x] = mix(xf0[x], xf1[x], smoothstep(0.f, 1.f, smooth)); \
859  } \
860  } \
861  } \
862 }
863 
865 CIRCLEOPEN_TRANSITION(16, uint16_t, 2)
866 
867 #define CIRCLECLOSE_TRANSITION(name, type, div) \
868 static void circleclose##name##_transition(AVFilterContext *ctx, \
869  const AVFrame *a, const AVFrame *b, AVFrame *out, \
870  float progress, \
871  int slice_start, int slice_end, int jobnr) \
872 { \
873  XFadeContext *s = ctx->priv; \
874  const int width = out->width; \
875  const int height = out->height; \
876  const float z = hypotf(width / 2, height / 2); \
877  const float p = (1.f - progress - 0.5f) * 3.f; \
878  \
879  for (int y = slice_start; y < slice_end; y++) { \
880  for (int x = 0; x < width; x++) { \
881  const float smooth = hypotf(x - width / 2, y - height / 2) / z + p; \
882  for (int p = 0; p < s->nb_planes; p++) { \
883  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
884  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
885  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
886  \
887  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
888  } \
889  } \
890  } \
891 }
892 
894 CIRCLECLOSE_TRANSITION(16, uint16_t, 2)
895 
896 #define VERTOPEN_TRANSITION(name, type, div) \
897 static void vertopen##name##_transition(AVFilterContext *ctx, \
898  const AVFrame *a, const AVFrame *b, AVFrame *out, \
899  float progress, \
900  int slice_start, int slice_end, int jobnr) \
901 { \
902  XFadeContext *s = ctx->priv; \
903  const int width = out->width; \
904  const float w2 = out->width / 2; \
905  \
906  for (int y = slice_start; y < slice_end; y++) { \
907  for (int x = 0; x < width; x++) { \
908  const float smooth = 2.f - fabsf((x - w2) / w2) - progress * 2.f; \
909  for (int p = 0; p < s->nb_planes; p++) { \
910  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
911  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
912  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
913  \
914  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
915  } \
916  } \
917  } \
918 }
919 
921 VERTOPEN_TRANSITION(16, uint16_t, 2)
922 
923 #define VERTCLOSE_TRANSITION(name, type, div) \
924 static void vertclose##name##_transition(AVFilterContext *ctx, \
925  const AVFrame *a, const AVFrame *b, AVFrame *out, \
926  float progress, \
927  int slice_start, int slice_end, int jobnr) \
928 { \
929  XFadeContext *s = ctx->priv; \
930  const int width = out->width; \
931  const float w2 = out->width / 2; \
932  \
933  for (int y = slice_start; y < slice_end; y++) { \
934  for (int x = 0; x < width; x++) { \
935  const float smooth = 1.f + fabsf((x - w2) / w2) - progress * 2.f; \
936  for (int p = 0; p < s->nb_planes; p++) { \
937  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
938  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
939  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
940  \
941  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
942  } \
943  } \
944  } \
945 }
946 
948 VERTCLOSE_TRANSITION(16, uint16_t, 2)
949 
950 #define HORZOPEN_TRANSITION(name, type, div) \
951 static void horzopen##name##_transition(AVFilterContext *ctx, \
952  const AVFrame *a, const AVFrame *b, AVFrame *out, \
953  float progress, \
954  int slice_start, int slice_end, int jobnr) \
955 { \
956  XFadeContext *s = ctx->priv; \
957  const int width = out->width; \
958  const float h2 = out->height / 2; \
959  \
960  for (int y = slice_start; y < slice_end; y++) { \
961  const float smooth = 2.f - fabsf((y - h2) / h2) - progress * 2.f; \
962  for (int x = 0; x < width; x++) { \
963  for (int p = 0; p < s->nb_planes; p++) { \
964  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
965  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
966  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
967  \
968  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
969  } \
970  } \
971  } \
972 }
973 
975 HORZOPEN_TRANSITION(16, uint16_t, 2)
976 
977 #define HORZCLOSE_TRANSITION(name, type, div) \
978 static void horzclose##name##_transition(AVFilterContext *ctx, \
979  const AVFrame *a, const AVFrame *b, AVFrame *out, \
980  float progress, \
981  int slice_start, int slice_end, int jobnr) \
982 { \
983  XFadeContext *s = ctx->priv; \
984  const int width = out->width; \
985  const float h2 = out->height / 2; \
986  \
987  for (int y = slice_start; y < slice_end; y++) { \
988  const float smooth = 1.f + fabsf((y - h2) / h2) - progress * 2.f; \
989  for (int x = 0; x < width; x++) { \
990  for (int p = 0; p < s->nb_planes; p++) { \
991  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
992  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
993  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
994  \
995  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
996  } \
997  } \
998  } \
999 }
1000 
1002 HORZCLOSE_TRANSITION(16, uint16_t, 2)
1003 
1004 static float frand(int x, int y)
1005 {
1006  const float r = sinf(x * 12.9898f + y * 78.233f) * 43758.545f;
1007 
1008  return r - floorf(r);
1009 }
1010 
1011 #define DISSOLVE_TRANSITION(name, type, div) \
1012 static void dissolve##name##_transition(AVFilterContext *ctx, \
1013  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1014  float progress, \
1015  int slice_start, int slice_end, int jobnr) \
1016 { \
1017  XFadeContext *s = ctx->priv; \
1018  const int width = out->width; \
1019  \
1020  for (int y = slice_start; y < slice_end; y++) { \
1021  for (int x = 0; x < width; x++) { \
1022  const float smooth = frand(x, y) * 2.f + progress * 2.f - 1.5f; \
1023  for (int p = 0; p < s->nb_planes; p++) { \
1024  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1025  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1026  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1027  \
1028  dst[x] = smooth >= 0.5f ? xf0[x] : xf1[x]; \
1029  } \
1030  } \
1031  } \
1032 }
1033 
1035 DISSOLVE_TRANSITION(16, uint16_t, 2)
1036 
1037 #define PIXELIZE_TRANSITION(name, type, div) \
1038 static void pixelize##name##_transition(AVFilterContext *ctx, \
1039  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1040  float progress, \
1041  int slice_start, int slice_end, int jobnr) \
1042 { \
1043  XFadeContext *s = ctx->priv; \
1044  const int w = out->width; \
1045  const int h = out->height; \
1046  const float d = fminf(progress, 1.f - progress); \
1047  const float dist = ceilf(d * 50.f) / 50.f; \
1048  const float sqx = 2.f * dist * FFMIN(w, h) / 20.f; \
1049  const float sqy = 2.f * dist * FFMIN(w, h) / 20.f; \
1050  \
1051  for (int y = slice_start; y < slice_end; y++) { \
1052  for (int x = 0; x < w; x++) { \
1053  int sx = dist > 0.f ? FFMIN((floorf(x / sqx) + .5f) * sqx, w - 1) : x; \
1054  int sy = dist > 0.f ? FFMIN((floorf(y / sqy) + .5f) * sqy, h - 1) : y; \
1055  for (int p = 0; p < s->nb_planes; p++) { \
1056  const type *xf0 = (const type *)(a->data[p] + sy * a->linesize[p]); \
1057  const type *xf1 = (const type *)(b->data[p] + sy * b->linesize[p]); \
1058  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1059  \
1060  dst[x] = mix(xf0[sx], xf1[sx], progress); \
1061  } \
1062  } \
1063  } \
1064 }
1065 
1067 PIXELIZE_TRANSITION(16, uint16_t, 2)
1068 
1069 #define DIAGTL_TRANSITION(name, type, div) \
1070 static void diagtl##name##_transition(AVFilterContext *ctx, \
1071  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1072  float progress, \
1073  int slice_start, int slice_end, int jobnr) \
1074 { \
1075  XFadeContext *s = ctx->priv; \
1076  const int width = out->width; \
1077  const float w = width; \
1078  const float h = out->height; \
1079  \
1080  for (int y = slice_start; y < slice_end; y++) { \
1081  for (int x = 0; x < width; x++) { \
1082  const float smooth = 1.f + x / w * y / h - progress * 2.f; \
1083  \
1084  for (int p = 0; p < s->nb_planes; p++) { \
1085  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1086  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1087  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1088  \
1089  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1090  } \
1091  } \
1092  } \
1093 }
1094 
1096 DIAGTL_TRANSITION(16, uint16_t, 2)
1097 
1098 #define DIAGTR_TRANSITION(name, type, div) \
1099 static void diagtr##name##_transition(AVFilterContext *ctx, \
1100  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1101  float progress, \
1102  int slice_start, int slice_end, int jobnr) \
1103 { \
1104  XFadeContext *s = ctx->priv; \
1105  const int width = out->width; \
1106  const float w = width; \
1107  const float h = out->height; \
1108  \
1109  for (int y = slice_start; y < slice_end; y++) { \
1110  for (int x = 0; x < width; x++) { \
1111  const float smooth = 1.f + (w - 1 - x) / w * y / h - progress * 2.f; \
1112  \
1113  for (int p = 0; p < s->nb_planes; p++) { \
1114  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1115  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1116  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1117  \
1118  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1119  } \
1120  } \
1121  } \
1122 }
1123 
1125 DIAGTR_TRANSITION(16, uint16_t, 2)
1126 
1127 #define DIAGBL_TRANSITION(name, type, div) \
1128 static void diagbl##name##_transition(AVFilterContext *ctx, \
1129  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1130  float progress, \
1131  int slice_start, int slice_end, int jobnr) \
1132 { \
1133  XFadeContext *s = ctx->priv; \
1134  const int width = out->width; \
1135  const float w = width; \
1136  const float h = out->height; \
1137  \
1138  for (int y = slice_start; y < slice_end; y++) { \
1139  for (int x = 0; x < width; x++) { \
1140  const float smooth = 1.f + x / w * (h - 1 - y) / h - progress * 2.f; \
1141  \
1142  for (int p = 0; p < s->nb_planes; p++) { \
1143  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1144  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1145  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1146  \
1147  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1148  } \
1149  } \
1150  } \
1151 }
1152 
1154 DIAGBL_TRANSITION(16, uint16_t, 2)
1155 
1156 #define DIAGBR_TRANSITION(name, type, div) \
1157 static void diagbr##name##_transition(AVFilterContext *ctx, \
1158  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1159  float progress, \
1160  int slice_start, int slice_end, int jobnr) \
1161 { \
1162  XFadeContext *s = ctx->priv; \
1163  const int width = out->width; \
1164  const float w = width; \
1165  const float h = out->height; \
1166  \
1167  for (int y = slice_start; y < slice_end; y++) { \
1168  for (int x = 0; x < width; x++) { \
1169  const float smooth = 1.f + (w - 1 - x) / w * (h - 1 - y) / h - \
1170  progress * 2.f; \
1171  \
1172  for (int p = 0; p < s->nb_planes; p++) { \
1173  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1174  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1175  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1176  \
1177  dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1178  } \
1179  } \
1180  } \
1181 }
1182 
1184 DIAGBR_TRANSITION(16, uint16_t, 2)
1185 
1186 #define HLSLICE_TRANSITION(name, type, div) \
1187 static void hlslice##name##_transition(AVFilterContext *ctx, \
1188  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1189  float progress, \
1190  int slice_start, int slice_end, int jobnr) \
1191 { \
1192  XFadeContext *s = ctx->priv; \
1193  const int width = out->width; \
1194  const float w = width; \
1195  \
1196  for (int y = slice_start; y < slice_end; y++) { \
1197  for (int x = 0; x < width; x++) { \
1198  const float smooth = smoothstep(-0.5f, 0.f, x / w - progress * 1.5f); \
1199  const float ss = smooth <= fract(10.f * x / w) ? 0.f : 1.f; \
1200  \
1201  for (int p = 0; p < s->nb_planes; p++) { \
1202  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1203  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1204  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1205  \
1206  dst[x] = mix(xf1[x], xf0[x], ss); \
1207  } \
1208  } \
1209  } \
1210 }
1211 
1213 HLSLICE_TRANSITION(16, uint16_t, 2)
1214 
1215 #define HRSLICE_TRANSITION(name, type, div) \
1216 static void hrslice##name##_transition(AVFilterContext *ctx, \
1217  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1218  float progress, \
1219  int slice_start, int slice_end, int jobnr) \
1220 { \
1221  XFadeContext *s = ctx->priv; \
1222  const int width = out->width; \
1223  const float w = width; \
1224  \
1225  for (int y = slice_start; y < slice_end; y++) { \
1226  for (int x = 0; x < width; x++) { \
1227  const float xx = (w - 1 - x) / w; \
1228  const float smooth = smoothstep(-0.5f, 0.f, xx - progress * 1.5f); \
1229  const float ss = smooth <= fract(10.f * xx) ? 0.f : 1.f; \
1230  \
1231  for (int p = 0; p < s->nb_planes; p++) { \
1232  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1233  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1234  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1235  \
1236  dst[x] = mix(xf1[x], xf0[x], ss); \
1237  } \
1238  } \
1239  } \
1240 }
1241 
1243 HRSLICE_TRANSITION(16, uint16_t, 2)
1244 
1245 #define VUSLICE_TRANSITION(name, type, div) \
1246 static void vuslice##name##_transition(AVFilterContext *ctx, \
1247  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1248  float progress, \
1249  int slice_start, int slice_end, int jobnr) \
1250 { \
1251  XFadeContext *s = ctx->priv; \
1252  const int width = out->width; \
1253  const float h = out->height; \
1254  \
1255  for (int y = slice_start; y < slice_end; y++) { \
1256  const float smooth = smoothstep(-0.5f, 0.f, y / h - progress * 1.5f); \
1257  const float ss = smooth <= fract(10.f * y / h) ? 0.f : 1.f; \
1258  \
1259  for (int x = 0; x < width; x++) { \
1260  for (int p = 0; p < s->nb_planes; p++) { \
1261  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1262  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1263  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1264  \
1265  dst[x] = mix(xf1[x], xf0[x], ss); \
1266  } \
1267  } \
1268  } \
1269 }
1270 
1272 VUSLICE_TRANSITION(16, uint16_t, 2)
1273 
1274 #define VDSLICE_TRANSITION(name, type, div) \
1275 static void vdslice##name##_transition(AVFilterContext *ctx, \
1276  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1277  float progress, \
1278  int slice_start, int slice_end, int jobnr) \
1279 { \
1280  XFadeContext *s = ctx->priv; \
1281  const int width = out->width; \
1282  const float h = out->height; \
1283  \
1284  for (int y = slice_start; y < slice_end; y++) { \
1285  const float yy = (h - 1 - y) / h; \
1286  const float smooth = smoothstep(-0.5f, 0.f, yy - progress * 1.5f); \
1287  const float ss = smooth <= fract(10.f * yy) ? 0.f : 1.f; \
1288  \
1289  for (int x = 0; x < width; x++) { \
1290  for (int p = 0; p < s->nb_planes; p++) { \
1291  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1292  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1293  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1294  \
1295  dst[x] = mix(xf1[x], xf0[x], ss); \
1296  } \
1297  } \
1298  } \
1299 }
1300 
1302 VDSLICE_TRANSITION(16, uint16_t, 2)
1303 
1304 #define HBLUR_TRANSITION(name, type, div) \
1305 static void hblur##name##_transition(AVFilterContext *ctx, \
1306  const AVFrame *a, const AVFrame *b, AVFrame *out, \
1307  float progress, \
1308  int slice_start, int slice_end, int jobnr) \
1309 { \
1310  XFadeContext *s = ctx->priv; \
1311  const int width = out->width; \
1312  const float prog = progress <= 0.5f ? progress * 2.f : (1.f - progress) * 2.f; \
1313  const int size = 1 + (width / 2) * prog; \
1314  \
1315  for (int y = slice_start; y < slice_end; y++) { \
1316  for (int p = 0; p < s->nb_planes; p++) { \
1317  const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1318  const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1319  type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1320  float sum0 = 0.f; \
1321  float sum1 = 0.f; \
1322  float cnt = size; \
1323  \
1324  for (int x = 0; x < size; x++) { \
1325  sum0 += xf0[x]; \
1326  sum1 += xf1[x]; \
1327  } \
1328  \
1329  for (int x = 0; x < width; x++) { \
1330  dst[x] = mix(sum0 / cnt, sum1 / cnt, progress); \
1331  \
1332  if (x + size < width) { \
1333  sum0 += xf0[x + size] - xf0[x]; \
1334  sum1 += xf1[x + size] - xf1[x]; \
1335  } else { \
1336  sum0 -= xf0[x]; \
1337  sum1 -= xf1[x]; \
1338  cnt--; \
1339  } \
1340  } \
1341  } \
1342  } \
1343 }
1344 
1346 HBLUR_TRANSITION(16, uint16_t, 2)
1347 
1348 static inline double getpix(void *priv, double x, double y, int plane, int nb)
1349 {
1350  XFadeContext *s = priv;
1351  AVFrame *in = s->xf[nb];
1352  const uint8_t *src = in->data[FFMIN(plane, s->nb_planes - 1)];
1353  int linesize = in->linesize[FFMIN(plane, s->nb_planes - 1)];
1354  const int w = in->width;
1355  const int h = in->height;
1356 
1357  int xi, yi;
1358 
1359  xi = av_clipd(x, 0, w - 1);
1360  yi = av_clipd(y, 0, h - 1);
1361 
1362  if (s->depth > 8) {
1363  const uint16_t *src16 = (const uint16_t*)src;
1364 
1365  linesize /= 2;
1366  return src16[xi + yi * linesize];
1367  } else {
1368  return src[xi + yi * linesize];
1369  }
1370 }
1371 
1372 static double a0(void *priv, double x, double y) { return getpix(priv, x, y, 0, 0); }
1373 static double a1(void *priv, double x, double y) { return getpix(priv, x, y, 1, 0); }
1374 static double a2(void *priv, double x, double y) { return getpix(priv, x, y, 2, 0); }
1375 static double a3(void *priv, double x, double y) { return getpix(priv, x, y, 3, 0); }
1376 
1377 static double b0(void *priv, double x, double y) { return getpix(priv, x, y, 0, 1); }
1378 static double b1(void *priv, double x, double y) { return getpix(priv, x, y, 1, 1); }
1379 static double b2(void *priv, double x, double y) { return getpix(priv, x, y, 2, 1); }
1380 static double b3(void *priv, double x, double y) { return getpix(priv, x, y, 3, 1); }
1381 
1382 static int config_output(AVFilterLink *outlink)
1383 {
1384  AVFilterContext *ctx = outlink->src;
1385  AVFilterLink *inlink0 = ctx->inputs[0];
1386  AVFilterLink *inlink1 = ctx->inputs[1];
1387  XFadeContext *s = ctx->priv;
1388  const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink0->format);
1389  int is_rgb;
1390 
1391  if (inlink0->format != inlink1->format) {
1392  av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n");
1393  return AVERROR(EINVAL);
1394  }
1395  if (inlink0->w != inlink1->w || inlink0->h != inlink1->h) {
1396  av_log(ctx, AV_LOG_ERROR, "First input link %s parameters "
1397  "(size %dx%d) do not match the corresponding "
1398  "second input link %s parameters (size %dx%d)\n",
1399  ctx->input_pads[0].name, inlink0->w, inlink0->h,
1400  ctx->input_pads[1].name, inlink1->w, inlink1->h);
1401  return AVERROR(EINVAL);
1402  }
1403 
1404  if (inlink0->time_base.num != inlink1->time_base.num ||
1405  inlink0->time_base.den != inlink1->time_base.den) {
1406  av_log(ctx, AV_LOG_ERROR, "First input link %s timebase "
1407  "(%d/%d) do not match the corresponding "
1408  "second input link %s timebase (%d/%d)\n",
1409  ctx->input_pads[0].name, inlink0->time_base.num, inlink0->time_base.den,
1410  ctx->input_pads[1].name, inlink1->time_base.num, inlink1->time_base.den);
1411  return AVERROR(EINVAL);
1412  }
1413 
1414  outlink->w = inlink0->w;
1415  outlink->h = inlink0->h;
1416  outlink->time_base = inlink0->time_base;
1417  outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
1418  outlink->frame_rate = inlink0->frame_rate;
1419 
1420  s->depth = pix_desc->comp[0].depth;
1421  is_rgb = !!(pix_desc->flags & AV_PIX_FMT_FLAG_RGB);
1422  s->nb_planes = av_pix_fmt_count_planes(inlink0->format);
1423  s->max_value = (1 << s->depth) - 1;
1424  s->black[0] = 0;
1425  s->black[1] = s->black[2] = is_rgb ? 0 : s->max_value / 2;
1426  s->black[3] = s->max_value;
1427  s->white[0] = s->white[3] = s->max_value;
1428  s->white[1] = s->white[2] = is_rgb ? s->max_value : s->max_value / 2;
1429 
1430  s->first_pts = s->last_pts = s->pts = AV_NOPTS_VALUE;
1431 
1432  if (s->duration)
1434  if (s->offset)
1436 
1437  switch (s->transition) {
1438  case CUSTOM: s->transitionf = s->depth <= 8 ? custom8_transition : custom16_transition; break;
1439  case FADE: s->transitionf = s->depth <= 8 ? fade8_transition : fade16_transition; break;
1440  case WIPELEFT: s->transitionf = s->depth <= 8 ? wipeleft8_transition : wipeleft16_transition; break;
1441  case WIPERIGHT: s->transitionf = s->depth <= 8 ? wiperight8_transition : wiperight16_transition; break;
1442  case WIPEUP: s->transitionf = s->depth <= 8 ? wipeup8_transition : wipeup16_transition; break;
1443  case WIPEDOWN: s->transitionf = s->depth <= 8 ? wipedown8_transition : wipedown16_transition; break;
1444  case SLIDELEFT: s->transitionf = s->depth <= 8 ? slideleft8_transition : slideleft16_transition; break;
1445  case SLIDERIGHT: s->transitionf = s->depth <= 8 ? slideright8_transition : slideright16_transition; break;
1446  case SLIDEUP: s->transitionf = s->depth <= 8 ? slideup8_transition : slideup16_transition; break;
1447  case SLIDEDOWN: s->transitionf = s->depth <= 8 ? slidedown8_transition : slidedown16_transition; break;
1448  case CIRCLECROP: s->transitionf = s->depth <= 8 ? circlecrop8_transition : circlecrop16_transition; break;
1449  case RECTCROP: s->transitionf = s->depth <= 8 ? rectcrop8_transition : rectcrop16_transition; break;
1450  case DISTANCE: s->transitionf = s->depth <= 8 ? distance8_transition : distance16_transition; break;
1451  case FADEBLACK: s->transitionf = s->depth <= 8 ? fadeblack8_transition : fadeblack16_transition; break;
1452  case FADEWHITE: s->transitionf = s->depth <= 8 ? fadewhite8_transition : fadewhite16_transition; break;
1453  case RADIAL: s->transitionf = s->depth <= 8 ? radial8_transition : radial16_transition; break;
1454  case SMOOTHLEFT: s->transitionf = s->depth <= 8 ? smoothleft8_transition : smoothleft16_transition; break;
1455  case SMOOTHRIGHT:s->transitionf = s->depth <= 8 ? smoothright8_transition: smoothright16_transition;break;
1456  case SMOOTHUP: s->transitionf = s->depth <= 8 ? smoothup8_transition : smoothup16_transition; break;
1457  case SMOOTHDOWN: s->transitionf = s->depth <= 8 ? smoothdown8_transition : smoothdown16_transition; break;
1458  case CIRCLEOPEN: s->transitionf = s->depth <= 8 ? circleopen8_transition : circleopen16_transition; break;
1459  case CIRCLECLOSE:s->transitionf = s->depth <= 8 ? circleclose8_transition: circleclose16_transition;break;
1460  case VERTOPEN: s->transitionf = s->depth <= 8 ? vertopen8_transition : vertopen16_transition; break;
1461  case VERTCLOSE: s->transitionf = s->depth <= 8 ? vertclose8_transition : vertclose16_transition; break;
1462  case HORZOPEN: s->transitionf = s->depth <= 8 ? horzopen8_transition : horzopen16_transition; break;
1463  case HORZCLOSE: s->transitionf = s->depth <= 8 ? horzclose8_transition : horzclose16_transition; break;
1464  case DISSOLVE: s->transitionf = s->depth <= 8 ? dissolve8_transition : dissolve16_transition; break;
1465  case PIXELIZE: s->transitionf = s->depth <= 8 ? pixelize8_transition : pixelize16_transition; break;
1466  case DIAGTL: s->transitionf = s->depth <= 8 ? diagtl8_transition : diagtl16_transition; break;
1467  case DIAGTR: s->transitionf = s->depth <= 8 ? diagtr8_transition : diagtr16_transition; break;
1468  case DIAGBL: s->transitionf = s->depth <= 8 ? diagbl8_transition : diagbl16_transition; break;
1469  case DIAGBR: s->transitionf = s->depth <= 8 ? diagbr8_transition : diagbr16_transition; break;
1470  case HLSLICE: s->transitionf = s->depth <= 8 ? hlslice8_transition : hlslice16_transition; break;
1471  case HRSLICE: s->transitionf = s->depth <= 8 ? hrslice8_transition : hrslice16_transition; break;
1472  case VUSLICE: s->transitionf = s->depth <= 8 ? vuslice8_transition : vuslice16_transition; break;
1473  case VDSLICE: s->transitionf = s->depth <= 8 ? vdslice8_transition : vdslice16_transition; break;
1474  case HBLUR: s->transitionf = s->depth <= 8 ? hblur8_transition : hblur16_transition; break;
1475  }
1476 
1477  if (s->transition == CUSTOM) {
1478  static const char *const func2_names[] = {
1479  "a0", "a1", "a2", "a3",
1480  "b0", "b1", "b2", "b3",
1481  NULL
1482  };
1483  double (*func2[])(void *, double, double) = {
1484  a0, a1, a2, a3,
1485  b0, b1, b2, b3,
1486  NULL };
1487  int ret;
1488 
1489  if (!s->custom_str)
1490  return AVERROR(EINVAL);
1491  ret = av_expr_parse(&s->e, s->custom_str, var_names,
1492  NULL, NULL, func2_names, func2, 0, ctx);
1493  if (ret < 0)
1494  return ret;
1495  }
1496 
1497  return 0;
1498 }
1499 
1500 static int xfade_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
1501 {
1502  XFadeContext *s = ctx->priv;
1503  AVFilterLink *outlink = ctx->outputs[0];
1504  ThreadData *td = arg;
1505  int slice_start = (outlink->h * jobnr ) / nb_jobs;
1506  int slice_end = (outlink->h * (jobnr+1)) / nb_jobs;
1507 
1508  s->transitionf(ctx, td->xf[0], td->xf[1], td->out, td->progress, slice_start, slice_end, jobnr);
1509 
1510  return 0;
1511 }
1512 
1514 {
1515  XFadeContext *s = ctx->priv;
1516  AVFilterLink *outlink = ctx->outputs[0];
1517  float progress = av_clipf(1.f - ((float)(s->pts - s->first_pts - s->offset_pts) / s->duration_pts), 0.f, 1.f);
1518  ThreadData td;
1519  AVFrame *out;
1520 
1521  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1522  if (!out)
1523  return AVERROR(ENOMEM);
1524 
1525  td.xf[0] = a, td.xf[1] = b, td.out = out, td.progress = progress;
1526  ctx->internal->execute(ctx, xfade_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
1527 
1528  out->pts = s->pts;
1529 
1530  return ff_filter_frame(outlink, out);
1531 }
1532 
1534 {
1535  XFadeContext *s = ctx->priv;
1536  AVFilterLink *outlink = ctx->outputs[0];
1537  AVFrame *in = NULL;
1538  int ret = 0, status;
1539  int64_t pts;
1540 
1541  FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
1542 
1543  if (s->xfade_is_over) {
1544  ret = ff_inlink_consume_frame(ctx->inputs[1], &in);
1545  if (ret < 0) {
1546  return ret;
1547  } else if (ret > 0) {
1548  in->pts = (in->pts - s->last_pts) + s->pts;
1549  return ff_filter_frame(outlink, in);
1550  } else if (ff_inlink_acknowledge_status(ctx->inputs[1], &status, &pts)) {
1551  ff_outlink_set_status(outlink, status, s->pts);
1552  return 0;
1553  } else if (!ret) {
1554  if (ff_outlink_frame_wanted(outlink)) {
1556  return 0;
1557  }
1558  }
1559  }
1560 
1561  if (ff_inlink_queued_frames(ctx->inputs[0]) > 0) {
1562  s->xf[0] = ff_inlink_peek_frame(ctx->inputs[0], 0);
1563  if (s->xf[0]) {
1564  if (s->first_pts == AV_NOPTS_VALUE) {
1565  s->first_pts = s->xf[0]->pts;
1566  }
1567  s->pts = s->xf[0]->pts;
1568  if (s->first_pts + s->offset_pts > s->xf[0]->pts) {
1569  s->xf[0] = NULL;
1570  s->need_second = 0;
1571  ff_inlink_consume_frame(ctx->inputs[0], &in);
1572  return ff_filter_frame(outlink, in);
1573  }
1574 
1575  s->need_second = 1;
1576  }
1577  }
1578 
1579  if (s->xf[0] && ff_inlink_queued_frames(ctx->inputs[1]) > 0) {
1580  ff_inlink_consume_frame(ctx->inputs[0], &s->xf[0]);
1581  ff_inlink_consume_frame(ctx->inputs[1], &s->xf[1]);
1582 
1583  s->last_pts = s->xf[1]->pts;
1584  s->pts = s->xf[0]->pts;
1585  if (s->xf[0]->pts - (s->first_pts + s->offset_pts) > s->duration_pts)
1586  s->xfade_is_over = 1;
1587  ret = xfade_frame(ctx, s->xf[0], s->xf[1]);
1588  av_frame_free(&s->xf[0]);
1589  av_frame_free(&s->xf[1]);
1590  return ret;
1591  }
1592 
1593  if (ff_inlink_queued_frames(ctx->inputs[0]) > 0 &&
1594  ff_inlink_queued_frames(ctx->inputs[1]) > 0) {
1595  ff_filter_set_ready(ctx, 100);
1596  return 0;
1597  }
1598 
1599  if (ff_outlink_frame_wanted(outlink)) {
1600  if (!s->eof[0] && ff_outlink_get_status(ctx->inputs[0])) {
1601  s->eof[0] = 1;
1602  s->xfade_is_over = 1;
1603  }
1604  if (!s->eof[1] && ff_outlink_get_status(ctx->inputs[1])) {
1605  s->eof[1] = 1;
1606  }
1607  if (!s->eof[0] && !s->xf[0])
1609  if (!s->eof[1] && (s->need_second || s->eof[0]))
1611  if (s->eof[0] && s->eof[1] && (
1612  ff_inlink_queued_frames(ctx->inputs[0]) <= 0 ||
1613  ff_inlink_queued_frames(ctx->inputs[1]) <= 0))
1615  return 0;
1616  }
1617 
1618  return FFERROR_NOT_READY;
1619 }
1620 
1621 static const AVFilterPad xfade_inputs[] = {
1622  {
1623  .name = "main",
1624  .type = AVMEDIA_TYPE_VIDEO,
1625  },
1626  {
1627  .name = "xfade",
1628  .type = AVMEDIA_TYPE_VIDEO,
1629  },
1630  { NULL }
1631 };
1632 
1633 static const AVFilterPad xfade_outputs[] = {
1634  {
1635  .name = "default",
1636  .type = AVMEDIA_TYPE_VIDEO,
1637  .config_props = config_output,
1638  },
1639  { NULL }
1640 };
1641 
1643  .name = "xfade",
1644  .description = NULL_IF_CONFIG_SMALL("Cross fade one video with another video."),
1645  .priv_size = sizeof(XFadeContext),
1646  .priv_class = &xfade_class,
1649  .uninit = uninit,
1650  .inputs = xfade_inputs,
1651  .outputs = xfade_outputs,
1653 };
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link&#39;s FIFO and update the link&#39;s stats.
Definition: avfilter.c:1492
#define NULL
Definition: coverity.c:32
AVFrame * out
Definition: af_adeclick.c:494
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2573
This structure describes decoded (raw) audio or video data.
Definition: frame.h:308
AVOption.
Definition: opt.h:248
#define AV_PIX_FMT_YUV444P14
Definition: pixfmt.h:409
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:419
Definition: vf_xfade.c:33
#define DIAGBR_TRANSITION(name, type, div)
Definition: vf_xfade.c:1156
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
misc image utilities
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2613
#define FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, filter)
Forward the status on an output link to all input links.
Definition: filters.h:212
Main libavfilter public API header.
#define PIXELIZE_TRANSITION(name, type, div)
Definition: vf_xfade.c:1037
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:168
int num
Numerator.
Definition: rational.h:59
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:415
static double a1(void *priv, double x, double y)
Definition: vf_xfade.c:1373
#define FLAGS
Definition: vf_xfade.c:146
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:36
#define WIPELEFT_TRANSITION(name, type, div)
Definition: vf_xfade.c:283
static int query_formats(AVFilterContext *ctx)
Definition: vf_xfade.c:111
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition: eval.c:685
return FFERROR_NOT_READY
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:99
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
Definition: filters.h:189
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Definition: avfilter.c:1618
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
#define AV_PIX_FMT_GRAY10
Definition: pixfmt.h:380
const char * name
Pad name.
Definition: internal.h:60
static int xfade_activate(AVFilterContext *ctx)
Definition: vf_xfade.c:1533
#define AV_PIX_FMT_GRAY12
Definition: pixfmt.h:381
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
#define HORZOPEN_TRANSITION(name, type, div)
Definition: vf_xfade.c:950
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1091
#define DIAGBL_TRANSITION(name, type, div)
Definition: vf_xfade.c:1127
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:117
uint8_t
#define av_cold
Definition: attributes.h:88
#define HBLUR_TRANSITION(name, type, div)
Definition: vf_xfade.c:1304
uint16_t white[4]
Definition: vf_xfade.c:94
AVOptions.
#define WIPEDOWN_TRANSITION(name, type, div)
Definition: vf_xfade.c:373
filter_frame For filters that do not use the activate() callback
#define f(width, name)
Definition: cbs_vp9.c:255
static double a2(void *priv, double x, double y)
Definition: vf_xfade.c:1374
#define SLIDEUP_TRANSITION(name, type, div)
Definition: vf_xfade.c:469
AVFilter ff_vf_xfade
Definition: vf_xfade.c:1642
int max_value
Definition: vf_xfade.c:92
AVFILTER_DEFINE_CLASS(xfade)
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:401
Definition: eval.c:157
static double a3(void *priv, double x, double y)
Definition: vf_xfade.c:1375
int need_second
Definition: vf_xfade.c:89
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:414
Definition: vf_xfade.c:68
#define WIPEUP_TRANSITION(name, type, div)
Definition: vf_xfade.c:343
#define FADE_TRANSITION(name, type, div)
Definition: vf_xfade.c:254
uint16_t black[4]
Definition: vf_xfade.c:93
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:412
#define WIPERIGHT_TRANSITION(name, type, div)
Definition: vf_xfade.c:313
the definition of that something depends on the semantic of the filter The callback must examine the status of the filter s links and proceed accordingly The status of output links is stored in the status_in and status_out fields and tested by the ff_outlink_frame_wanted() function.If this function returns true
#define av_log(a,...)
A filter pad used for either input or output.
Definition: internal.h:54
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
int64_t duration_pts
Definition: vf_xfade.c:83
#define src
Definition: vp8dsp.c:254
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
Definition: avfilter.c:1447
static float mix(float a, float b, float mix)
Definition: vf_xfade.c:235
AVFilterPad * input_pads
array of input pads
Definition: avfilter.h:345
#define DIAGTL_TRANSITION(name, type, div)
Definition: vf_xfade.c:1069
int width
Definition: frame.h:366
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:600
#define td
Definition: regdef.h:70
void(* transitionf)(AVFilterContext *ctx, const AVFrame *a, const AVFrame *b, AVFrame *out, float progress, int slice_start, int slice_end, int jobnr)
Definition: vf_xfade.c:96
int64_t first_pts
Definition: vf_xfade.c:85
#define HRSLICE_TRANSITION(name, type, div)
Definition: vf_xfade.c:1215
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_xfade.c:138
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
Definition: pixdesc.h:148
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:153
#define CUSTOM_TRANSITION(name, type, div)
Definition: vf_xfade.c:195
const char * r
Definition: vf_curves.c:114
void * priv
private data for use by the filter
Definition: avfilter.h:353
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:116
const AVFrame * xf[2]
Definition: vf_xfade.c:106
#define HORZCLOSE_TRANSITION(name, type, div)
Definition: vf_xfade.c:977
#define AV_PIX_FMT_YUVA444P16
Definition: pixfmt.h:443
const char * arg
Definition: jacosubdec.c:66
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:420
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:402
static int xfade_frame(AVFilterContext *ctx, AVFrame *a, AVFrame *b)
Definition: vf_xfade.c:1513
#define VUSLICE_TRANSITION(name, type, div)
Definition: vf_xfade.c:1245
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:421
static double a0(void *priv, double x, double y)
Definition: vf_xfade.c:1372
int64_t pts
Definition: vf_xfade.c:87
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
#define b
Definition: input.c:41
XFadeTransitions
Definition: vf_xfade.c:31
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:418
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:800
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:383
#define FFMIN(a, b)
Definition: common.h:96
#define xi(width, name, var, range_min, range_max, subs,...)
Definition: cbs_h2645.c:396
#define AV_PIX_FMT_YUVA444P12
Definition: pixfmt.h:440
uint8_t w
Definition: llviddspenc.c:38
typedef void(APIENTRY *FF_PFNGLACTIVETEXTUREPROC)(GLenum texture)
float progress
Definition: vf_xfade.c:108
AVFormatContext * ctx
Definition: movenc.c:48
static double b0(void *priv, double x, double y)
Definition: vf_xfade.c:1377
#define SLIDELEFT_TRANSITION(name, type, div)
Definition: vf_xfade.c:403
#define SMOOTHDOWN_TRANSITION(name, type, div)
Definition: vf_xfade.c:811
#define s(width, name)
Definition: cbs_vp9.c:257
static float fract(float a)
Definition: vf_xfade.c:240
#define AV_PIX_FMT_YUVA444P10
Definition: pixfmt.h:438
static const char *const var_names[]
Definition: vf_xfade.c:102
int64_t duration
Definition: vf_xfade.c:76
#define CIRCLECLOSE_TRANSITION(name, type, div)
Definition: vf_xfade.c:867
int64_t last_pts
Definition: vf_xfade.c:86
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:417
AVFrame * ff_inlink_peek_frame(AVFilterLink *link, size_t idx)
Access a frame in the link fifo without consuming it.
Definition: avfilter.c:1531
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
#define FADEBLACK_TRANSITION(name, type, div)
Definition: vf_xfade.c:634
static float frand(int x, int y)
Definition: vf_xfade.c:1004
static double b1(void *priv, double x, double y)
Definition: vf_xfade.c:1378
#define CIRCLEOPEN_TRANSITION(name, type, div)
Definition: vf_xfade.c:838
#define OFFSET(x)
Definition: vf_xfade.c:145
#define sinf(x)
Definition: libm.h:419
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:336
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:260
Used for passing data between threads.
Definition: dsddec.c:67
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:339
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:177
static int config_output(AVFilterLink *outlink)
Definition: vf_xfade.c:1382
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
#define SMOOTHUP_TRANSITION(name, type, div)
Definition: vf_xfade.c:784
#define SLIDEDOWN_TRANSITION(name, type, div)
Definition: vf_xfade.c:500
#define HLSLICE_TRANSITION(name, type, div)
Definition: vf_xfade.c:1186
double(* func2[])(void *, double, double)
Definition: af_afftfilt.c:121
int xfade_is_over
Definition: vf_xfade.c:88
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31))))#define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac){}void ff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map){AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);return NULL;}return ac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;}int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){int use_generic=1;int len=in->nb_samples;int p;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
static const AVOption xfade_options[]
Definition: vf_xfade.c:148
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
int ff_outlink_get_status(AVFilterLink *link)
Get the status on an output link.
Definition: avfilter.c:1641
AVExpr * e
Definition: vf_xfade.c:99
int transition
Definition: vf_xfade.c:75
they must not be accessed directly The fifo field contains the frames that are queued in the input for processing by the filter The status_in and status_out fields contains the queued status(EOF or error) of the link
static double b3(void *priv, double x, double y)
Definition: vf_xfade.c:1380
const char * name
Filter name.
Definition: avfilter.h:148
int64_t offset_pts
Definition: vf_xfade.c:84
size_t ff_inlink_queued_frames(AVFilterLink *link)
Get the number of frames available on the link.
Definition: avfilter.c:1462
#define RECTCROP_TRANSITION(name, type, div)
Definition: vf_xfade.c:564
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:270
char * custom_str
Definition: vf_xfade.c:78
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:416
#define flags(name, subs,...)
Definition: cbs_av1.c:560
int nb_planes
Definition: vf_xfade.c:80
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:378
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:406
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:322
static float smoothstep(float edge0, float edge1, float x)
Definition: vf_xfade.c:245
int64_t offset
Definition: vf_xfade.c:77
Y , 8bpp.
Definition: pixfmt.h:74
#define FADEWHITE_TRANSITION(name, type, div)
Definition: vf_xfade.c:667
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:215
#define DISSOLVE_TRANSITION(name, type, div)
Definition: vf_xfade.c:1011
static int xfade_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_xfade.c:1500
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.
Definition: avfilter.c:193
#define AV_PIX_FMT_YUVA444P9
Definition: pixfmt.h:435
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition: pixfmt.h:80
int den
Denominator.
Definition: rational.h:60
int eof[2]
Definition: vf_xfade.c:90
avfilter_execute_func * execute
Definition: internal.h:144
static const char *const func2_names[]
Definition: af_afftfilt.c:120
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2039
#define SMOOTHRIGHT_TRANSITION(name, type, div)
Definition: vf_xfade.c:756
pixel format definitions
#define CIRCLECROP_TRANSITION(name, type, div)
Definition: vf_xfade.c:531
#define VERTOPEN_TRANSITION(name, type, div)
Definition: vf_xfade.c:896
#define SLIDERIGHT_TRANSITION(name, type, div)
Definition: vf_xfade.c:436
static const AVFilterPad xfade_inputs[]
Definition: vf_xfade.c:1621
static const AVFilterPad xfade_outputs[]
Definition: vf_xfade.c:1633
A list of supported formats for one end of a filter link.
Definition: formats.h:64
#define VERTCLOSE_TRANSITION(name, type, div)
Definition: vf_xfade.c:923
AVFrame * xf[2]
Definition: vf_xfade.c:91
An instance of a filter.
Definition: avfilter.h:338
int height
Definition: frame.h:366
FILE * out
Definition: movenc.c:54
#define VDSLICE_TRANSITION(name, type, div)
Definition: vf_xfade.c:1274
#define DISTANCE_TRANSITION(name, type, div)
Definition: vf_xfade.c:599
#define RADIAL_TRANSITION(name, type, div)
Definition: vf_xfade.c:700
internal API functions
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
int depth
Number of bits in the component.
Definition: pixdesc.h:58
#define DIAGTR_TRANSITION(name, type, div)
Definition: vf_xfade.c:1098
static double getpix(void *priv, double x, double y, int plane, int nb)
Definition: vf_xfade.c:1348
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
#define SMOOTHLEFT_TRANSITION(name, type, div)
Definition: vf_xfade.c:728
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
simple arithmetic expression evaluator
static double b2(void *priv, double x, double y)
Definition: vf_xfade.c:1379