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