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