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,
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
#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
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:281
static int query_formats(AVFilterContext *ctx)
Definition: vf_xfade.c:110
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:1602
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
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: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
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: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 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
#define b
Definition: input.c:41
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
typedef void(APIENTRY *FF_PFNGLACTIVETEXTUREPROC)(GLenum texture)
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
#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
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
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
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: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
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: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:2043
#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
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: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