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