Go to the documentation of this file.
106 int slice_start,
int slice_end,
int jobnr);
111 static const char *
const var_names[] = {
"X",
"Y",
"W",
"H",
"A",
"B",
"PLANE",
"P",
NULL };
146 #define OFFSET(x) offsetof(XFadeContext, x)
147 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
204 #define CUSTOM_TRANSITION(name, type, div) \
205 static void custom##name##_transition(AVFilterContext *ctx, \
206 const AVFrame *a, const AVFrame *b, AVFrame *out, \
208 int slice_start, int slice_end, int jobnr) \
210 XFadeContext *s = ctx->priv; \
211 const int height = slice_end - slice_start; \
213 double values[VAR_VARS_NB]; \
214 values[VAR_W] = out->width; \
215 values[VAR_H] = out->height; \
216 values[VAR_PROGRESS] = progress; \
218 for (int p = 0; p < s->nb_planes; p++) { \
219 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
220 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
221 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
223 values[VAR_PLANE] = p; \
225 for (int y = 0; y < height; y++) { \
226 values[VAR_Y] = slice_start + y; \
227 for (int x = 0; x < out->width; x++) { \
229 values[VAR_A] = xf0[x]; \
230 values[VAR_B] = xf1[x]; \
231 dst[x] = av_expr_eval(s->e, values, s); \
234 dst += out->linesize[p] / div; \
235 xf0 += a->linesize[p] / div; \
236 xf1 += b->linesize[p] / div; \
244 static inline
float mix(
float a,
float b,
float mix)
254 static inline float smoothstep(
float edge0,
float edge1,
float x)
258 t =
av_clipf((x - edge0) / (edge1 - edge0), 0.
f, 1.
f);
260 return t * t * (3.f - 2.f * t);
263 #define FADE_TRANSITION(name, type, div) \
264 static void fade##name##_transition(AVFilterContext *ctx, \
265 const AVFrame *a, const AVFrame *b, AVFrame *out, \
267 int slice_start, int slice_end, int jobnr) \
269 XFadeContext *s = ctx->priv; \
270 const int height = slice_end - slice_start; \
272 for (int p = 0; p < s->nb_planes; p++) { \
273 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
274 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
275 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
277 for (int y = 0; y < height; y++) { \
278 for (int x = 0; x < out->width; x++) { \
279 dst[x] = mix(xf0[x], xf1[x], progress); \
282 dst += out->linesize[p] / div; \
283 xf0 += a->linesize[p] / div; \
284 xf1 += b->linesize[p] / div; \
292 #define WIPELEFT_TRANSITION(name, type, div) \
293 static void wipeleft##name##_transition(AVFilterContext *ctx, \
294 const AVFrame *a, const AVFrame *b, AVFrame *out, \
296 int slice_start, int slice_end, int jobnr) \
298 XFadeContext *s = ctx->priv; \
299 const int height = slice_end - slice_start; \
300 const int z = out->width * progress; \
302 for (int p = 0; p < s->nb_planes; p++) { \
303 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
304 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
305 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
307 for (int y = 0; y < height; y++) { \
308 for (int x = 0; x < out->width; x++) { \
309 dst[x] = x > z ? xf1[x] : xf0[x]; \
312 dst += out->linesize[p] / div; \
313 xf0 += a->linesize[p] / div; \
314 xf1 += b->linesize[p] / div; \
322 #define WIPERIGHT_TRANSITION(name, type, div) \
323 static void wiperight##name##_transition(AVFilterContext *ctx, \
324 const AVFrame *a, const AVFrame *b, AVFrame *out, \
326 int slice_start, int slice_end, int jobnr) \
328 XFadeContext *s = ctx->priv; \
329 const int height = slice_end - slice_start; \
330 const int z = out->width * (1.f - progress); \
332 for (int p = 0; p < s->nb_planes; p++) { \
333 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
334 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
335 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
337 for (int y = 0; y < height; y++) { \
338 for (int x = 0; x < out->width; x++) { \
339 dst[x] = x > z ? xf0[x] : xf1[x]; \
342 dst += out->linesize[p] / div; \
343 xf0 += a->linesize[p] / div; \
344 xf1 += b->linesize[p] / div; \
352 #define WIPEUP_TRANSITION(name, type, div) \
353 static void wipeup##name##_transition(AVFilterContext *ctx, \
354 const AVFrame *a, const AVFrame *b, AVFrame *out, \
356 int slice_start, int slice_end, int jobnr) \
358 XFadeContext *s = ctx->priv; \
359 const int height = slice_end - slice_start; \
360 const int z = out->height * progress; \
362 for (int p = 0; p < s->nb_planes; p++) { \
363 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
364 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
365 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
367 for (int y = 0; y < height; y++) { \
368 for (int x = 0; x < out->width; x++) { \
369 dst[x] = slice_start + y > z ? xf1[x] : xf0[x]; \
372 dst += out->linesize[p] / div; \
373 xf0 += a->linesize[p] / div; \
374 xf1 += b->linesize[p] / div; \
382 #define WIPEDOWN_TRANSITION(name, type, div) \
383 static void wipedown##name##_transition(AVFilterContext *ctx, \
384 const AVFrame *a, const AVFrame *b, AVFrame *out, \
386 int slice_start, int slice_end, int jobnr) \
388 XFadeContext *s = ctx->priv; \
389 const int height = slice_end - slice_start; \
390 const int z = out->height * (1.f - progress); \
392 for (int p = 0; p < s->nb_planes; p++) { \
393 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
394 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
395 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
397 for (int y = 0; y < height; y++) { \
398 for (int x = 0; x < out->width; x++) { \
399 dst[x] = slice_start + y > z ? xf0[x] : xf1[x]; \
402 dst += out->linesize[p] / div; \
403 xf0 += a->linesize[p] / div; \
404 xf1 += b->linesize[p] / div; \
412 #define SLIDELEFT_TRANSITION(name, type, div) \
413 static void slideleft##name##_transition(AVFilterContext *ctx, \
414 const AVFrame *a, const AVFrame *b, AVFrame *out, \
416 int slice_start, int slice_end, int jobnr) \
418 XFadeContext *s = ctx->priv; \
419 const int height = slice_end - slice_start; \
420 const int width = out->width; \
421 const int z = -progress * width; \
423 for (int p = 0; p < s->nb_planes; p++) { \
424 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
425 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
426 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
428 for (int y = 0; y < height; y++) { \
429 for (int x = 0; x < width; x++) { \
430 const int zx = z + x; \
431 const int zz = zx % width + width * (zx < 0); \
432 dst[x] = (zx > 0) && (zx < width) ? xf1[zz] : xf0[zz]; \
435 dst += out->linesize[p] / div; \
436 xf0 += a->linesize[p] / div; \
437 xf1 += b->linesize[p] / div; \
445 #define SLIDERIGHT_TRANSITION(name, type, div) \
446 static void slideright##name##_transition(AVFilterContext *ctx, \
447 const AVFrame *a, const AVFrame *b, AVFrame *out, \
449 int slice_start, int slice_end, int jobnr) \
451 XFadeContext *s = ctx->priv; \
452 const int height = slice_end - slice_start; \
453 const int width = out->width; \
454 const int z = progress * width; \
456 for (int p = 0; p < s->nb_planes; p++) { \
457 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
458 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
459 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
461 for (int y = 0; y < height; y++) { \
462 for (int x = 0; x < out->width; x++) { \
463 const int zx = z + x; \
464 const int zz = zx % width + width * (zx < 0); \
465 dst[x] = (zx > 0) && (zx < width) ? xf1[zz] : xf0[zz]; \
468 dst += out->linesize[p] / div; \
469 xf0 += a->linesize[p] / div; \
470 xf1 += b->linesize[p] / div; \
478 #define SLIDEUP_TRANSITION(name, type, div) \
479 static void slideup##name##_transition(AVFilterContext *ctx, \
480 const AVFrame *a, const AVFrame *b, AVFrame *out, \
482 int slice_start, int slice_end, int jobnr) \
484 XFadeContext *s = ctx->priv; \
485 const int height = out->height; \
486 const int z = -progress * height; \
488 for (int p = 0; p < s->nb_planes; p++) { \
489 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
491 for (int y = slice_start; y < slice_end; y++) { \
492 const int zy = z + y; \
493 const int zz = zy % height + height * (zy < 0); \
494 const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
495 const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \
497 for (int x = 0; x < out->width; x++) { \
498 dst[x] = (zy > 0) && (zy < height) ? xf1[x] : xf0[x]; \
501 dst += out->linesize[p] / div; \
509 #define SLIDEDOWN_TRANSITION(name, type, div) \
510 static void slidedown##name##_transition(AVFilterContext *ctx, \
511 const AVFrame *a, const AVFrame *b, AVFrame *out, \
513 int slice_start, int slice_end, int jobnr) \
515 XFadeContext *s = ctx->priv; \
516 const int height = out->height; \
517 const int z = progress * height; \
519 for (int p = 0; p < s->nb_planes; p++) { \
520 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
522 for (int y = slice_start; y < slice_end; y++) { \
523 const int zy = z + y; \
524 const int zz = zy % height + height * (zy < 0); \
525 const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
526 const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \
528 for (int x = 0; x < out->width; x++) { \
529 dst[x] = (zy > 0) && (zy < height) ? xf1[x] : xf0[x]; \
532 dst += out->linesize[p] / div; \
540 #define CIRCLECROP_TRANSITION(name, type, div) \
541 static void circlecrop##name##_transition(AVFilterContext *ctx, \
542 const AVFrame *a, const AVFrame *b, AVFrame *out, \
544 int slice_start, int slice_end, int jobnr) \
546 XFadeContext *s = ctx->priv; \
547 const int width = out->width; \
548 const int height = out->height; \
549 float z = powf(2.f * fabsf(progress - 0.5f), 3.f) * hypotf(width/2, height/2); \
551 for (int p = 0; p < s->nb_planes; p++) { \
552 const int bg = s->black[p]; \
553 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
555 for (int y = slice_start; y < slice_end; y++) { \
556 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
557 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
559 for (int x = 0; x < width; x++) { \
560 float dist = hypotf(x - width / 2, y - height / 2); \
561 int val = progress < 0.5f ? xf1[x] : xf0[x]; \
562 dst[x] = (z < dist) ? bg : val; \
565 dst += out->linesize[p] / div; \
573 #define RECTCROP_TRANSITION(name, type, div) \
574 static void rectcrop##name##_transition(AVFilterContext *ctx, \
575 const AVFrame *a, const AVFrame *b, AVFrame *out, \
577 int slice_start, int slice_end, int jobnr) \
579 XFadeContext *s = ctx->priv; \
580 const int width = out->width; \
581 const int height = out->height; \
582 int zh = fabsf(progress - 0.5f) * height; \
583 int zw = fabsf(progress - 0.5f) * width; \
585 for (int p = 0; p < s->nb_planes; p++) { \
586 const int bg = s->black[p]; \
587 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
589 for (int y = slice_start; y < slice_end; y++) { \
590 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
591 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
593 for (int x = 0; x < width; x++) { \
594 int dist = FFABS(x - width / 2) < zw && \
595 FFABS(y - height / 2) < zh; \
596 int val = progress < 0.5f ? xf1[x] : xf0[x]; \
597 dst[x] = !dist ? bg : val; \
600 dst += out->linesize[p] / div; \
608 #define DISTANCE_TRANSITION(name, type, div) \
609 static void distance##name##_transition(AVFilterContext *ctx, \
610 const AVFrame *a, const AVFrame *b, AVFrame *out, \
612 int slice_start, int slice_end, int jobnr) \
614 XFadeContext *s = ctx->priv; \
615 const int width = out->width; \
616 const float max = s->max_value; \
618 for (int y = slice_start; y < slice_end; y++) { \
619 for (int x = 0; x < width; x++) { \
621 for (int p = 0; p < s->nb_planes; p++) { \
622 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
623 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
625 dist += (xf0[x] / max - xf1[x] / max) * \
626 (xf0[x] / max - xf1[x] / max); \
629 dist = sqrtf(dist) <= progress; \
630 for (int p = 0; p < s->nb_planes; p++) { \
631 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
632 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
633 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
634 dst[x] = mix(mix(xf0[x], xf1[x], dist), xf1[x], progress); \
643 #define FADEBLACK_TRANSITION(name, type, div) \
644 static void fadeblack##name##_transition(AVFilterContext *ctx, \
645 const AVFrame *a, const AVFrame *b, AVFrame *out, \
647 int slice_start, int slice_end, int jobnr) \
649 XFadeContext *s = ctx->priv; \
650 const int height = slice_end - slice_start; \
651 const float phase = 0.2f; \
653 for (int p = 0; p < s->nb_planes; p++) { \
654 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
655 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
656 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
657 const int bg = s->black[p]; \
659 for (int y = 0; y < height; y++) { \
660 for (int x = 0; x < out->width; x++) { \
661 dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)), \
662 mix(bg, xf1[x], smoothstep(phase, 1.f, progress)), \
666 dst += out->linesize[p] / div; \
667 xf0 += a->linesize[p] / div; \
668 xf1 += b->linesize[p] / div; \
676 #define FADEWHITE_TRANSITION(name, type, div) \
677 static void fadewhite##name##_transition(AVFilterContext *ctx, \
678 const AVFrame *a, const AVFrame *b, AVFrame *out, \
680 int slice_start, int slice_end, int jobnr) \
682 XFadeContext *s = ctx->priv; \
683 const int height = slice_end - slice_start; \
684 const float phase = 0.2f; \
686 for (int p = 0; p < s->nb_planes; p++) { \
687 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
688 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
689 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
690 const int bg = s->white[p]; \
692 for (int y = 0; y < height; y++) { \
693 for (int x = 0; x < out->width; x++) { \
694 dst[x] = mix(mix(xf0[x], bg, smoothstep(1.f-phase, 1.f, progress)), \
695 mix(bg, xf1[x], smoothstep(phase, 1.f, progress)), \
699 dst += out->linesize[p] / div; \
700 xf0 += a->linesize[p] / div; \
701 xf1 += b->linesize[p] / div; \
709 #define RADIAL_TRANSITION(name, type, div) \
710 static void radial##name##_transition(AVFilterContext *ctx, \
711 const AVFrame *a, const AVFrame *b, AVFrame *out, \
713 int slice_start, int slice_end, int jobnr) \
715 XFadeContext *s = ctx->priv; \
716 const int width = out->width; \
717 const int height = out->height; \
719 for (int y = slice_start; y < slice_end; y++) { \
720 for (int x = 0; x < width; x++) { \
721 const float smooth = atan2f(x - width / 2, y - height / 2) - \
722 (progress - 0.5f) * (M_PI * 2.5f); \
723 for (int p = 0; p < s->nb_planes; p++) { \
724 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
725 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
726 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
728 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
737 #define SMOOTHLEFT_TRANSITION(name, type, div) \
738 static void smoothleft##name##_transition(AVFilterContext *ctx, \
739 const AVFrame *a, const AVFrame *b, AVFrame *out, \
741 int slice_start, int slice_end, int jobnr) \
743 XFadeContext *s = ctx->priv; \
744 const int width = out->width; \
745 const float w = width; \
747 for (int y = slice_start; y < slice_end; y++) { \
748 for (int x = 0; x < width; x++) { \
749 const float smooth = 1.f + x / w - progress * 2.f; \
751 for (int p = 0; p < s->nb_planes; p++) { \
752 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
753 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
754 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
756 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
765 #define SMOOTHRIGHT_TRANSITION(name, type, div) \
766 static void smoothright##name##_transition(AVFilterContext *ctx, \
767 const AVFrame *a, const AVFrame *b, AVFrame *out, \
769 int slice_start, int slice_end, int jobnr) \
771 XFadeContext *s = ctx->priv; \
772 const int width = out->width; \
773 const float w = width; \
775 for (int y = slice_start; y < slice_end; y++) { \
776 for (int x = 0; x < width; x++) { \
777 const float smooth = 1.f + (w - 1 - x) / w - progress * 2.f; \
779 for (int p = 0; p < s->nb_planes; p++) { \
780 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
781 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
782 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
784 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
793 #define SMOOTHUP_TRANSITION(name, type, div) \
794 static void smoothup##name##_transition(AVFilterContext *ctx, \
795 const AVFrame *a, const AVFrame *b, AVFrame *out, \
797 int slice_start, int slice_end, int jobnr) \
799 XFadeContext *s = ctx->priv; \
800 const int width = out->width; \
801 const float h = out->height; \
803 for (int y = slice_start; y < slice_end; y++) { \
804 const float smooth = 1.f + y / h - progress * 2.f; \
805 for (int x = 0; x < width; x++) { \
806 for (int p = 0; p < s->nb_planes; p++) { \
807 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
808 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
809 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
811 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
820 #define SMOOTHDOWN_TRANSITION(name, type, div) \
821 static void smoothdown##name##_transition(AVFilterContext *ctx, \
822 const AVFrame *a, const AVFrame *b, AVFrame *out, \
824 int slice_start, int slice_end, int jobnr) \
826 XFadeContext *s = ctx->priv; \
827 const int width = out->width; \
828 const float h = out->height; \
830 for (int y = slice_start; y < slice_end; y++) { \
831 const float smooth = 1.f + (h - 1 - y) / h - progress * 2.f; \
832 for (int x = 0; x < width; x++) { \
833 for (int p = 0; p < s->nb_planes; p++) { \
834 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
835 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
836 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
838 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
847 #define CIRCLEOPEN_TRANSITION(name, type, div) \
848 static void circleopen##name##_transition(AVFilterContext *ctx, \
849 const AVFrame *a, const AVFrame *b, AVFrame *out, \
851 int slice_start, int slice_end, int jobnr) \
853 XFadeContext *s = ctx->priv; \
854 const int width = out->width; \
855 const int height = out->height; \
856 const float z = hypotf(width / 2, height / 2); \
857 const float p = (progress - 0.5f) * 3.f; \
859 for (int y = slice_start; y < slice_end; y++) { \
860 for (int x = 0; x < width; x++) { \
861 const float smooth = hypotf(x - width / 2, y - height / 2) / z + p; \
862 for (int p = 0; p < s->nb_planes; p++) { \
863 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
864 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
865 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
867 dst[x] = mix(xf0[x], xf1[x], smoothstep(0.f, 1.f, smooth)); \
876 #define CIRCLECLOSE_TRANSITION(name, type, div) \
877 static void circleclose##name##_transition(AVFilterContext *ctx, \
878 const AVFrame *a, const AVFrame *b, AVFrame *out, \
880 int slice_start, int slice_end, int jobnr) \
882 XFadeContext *s = ctx->priv; \
883 const int width = out->width; \
884 const int height = out->height; \
885 const float z = hypotf(width / 2, height / 2); \
886 const float p = (1.f - progress - 0.5f) * 3.f; \
888 for (int y = slice_start; y < slice_end; y++) { \
889 for (int x = 0; x < width; x++) { \
890 const float smooth = hypotf(x - width / 2, y - height / 2) / z + p; \
891 for (int p = 0; p < s->nb_planes; p++) { \
892 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
893 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
894 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
896 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
905 #define VERTOPEN_TRANSITION(name, type, div) \
906 static void vertopen##name##_transition(AVFilterContext *ctx, \
907 const AVFrame *a, const AVFrame *b, AVFrame *out, \
909 int slice_start, int slice_end, int jobnr) \
911 XFadeContext *s = ctx->priv; \
912 const int width = out->width; \
913 const float w2 = out->width / 2; \
915 for (int y = slice_start; y < slice_end; y++) { \
916 for (int x = 0; x < width; x++) { \
917 const float smooth = 2.f - fabsf((x - w2) / w2) - progress * 2.f; \
918 for (int p = 0; p < s->nb_planes; p++) { \
919 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
920 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
921 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
923 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
932 #define VERTCLOSE_TRANSITION(name, type, div) \
933 static void vertclose##name##_transition(AVFilterContext *ctx, \
934 const AVFrame *a, const AVFrame *b, AVFrame *out, \
936 int slice_start, int slice_end, int jobnr) \
938 XFadeContext *s = ctx->priv; \
939 const int width = out->width; \
940 const float w2 = out->width / 2; \
942 for (int y = slice_start; y < slice_end; y++) { \
943 for (int x = 0; x < width; x++) { \
944 const float smooth = 1.f + fabsf((x - w2) / w2) - progress * 2.f; \
945 for (int p = 0; p < s->nb_planes; p++) { \
946 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
947 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
948 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
950 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
959 #define HORZOPEN_TRANSITION(name, type, div) \
960 static void horzopen##name##_transition(AVFilterContext *ctx, \
961 const AVFrame *a, const AVFrame *b, AVFrame *out, \
963 int slice_start, int slice_end, int jobnr) \
965 XFadeContext *s = ctx->priv; \
966 const int width = out->width; \
967 const float h2 = out->height / 2; \
969 for (int y = slice_start; y < slice_end; y++) { \
970 const float smooth = 2.f - fabsf((y - h2) / h2) - progress * 2.f; \
971 for (int x = 0; x < width; x++) { \
972 for (int p = 0; p < s->nb_planes; p++) { \
973 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
974 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
975 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
977 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
986 #define HORZCLOSE_TRANSITION(name, type, div) \
987 static void horzclose##name##_transition(AVFilterContext *ctx, \
988 const AVFrame *a, const AVFrame *b, AVFrame *out, \
990 int slice_start, int slice_end, int jobnr) \
992 XFadeContext *s = ctx->priv; \
993 const int width = out->width; \
994 const float h2 = out->height / 2; \
996 for (int y = slice_start; y < slice_end; y++) { \
997 const float smooth = 1.f + fabsf((y - h2) / h2) - progress * 2.f; \
998 for (int x = 0; x < width; x++) { \
999 for (int p = 0; p < s->nb_planes; p++) { \
1000 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1001 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1002 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1004 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1015 const float r =
sinf(x * 12.9898
f + y * 78.233
f) * 43758.545f;
1020 #define DISSOLVE_TRANSITION(name, type, div) \
1021 static void dissolve##name##_transition(AVFilterContext *ctx, \
1022 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1024 int slice_start, int slice_end, int jobnr) \
1026 XFadeContext *s = ctx->priv; \
1027 const int width = out->width; \
1029 for (int y = slice_start; y < slice_end; y++) { \
1030 for (int x = 0; x < width; x++) { \
1031 const float smooth = frand(x, y) * 2.f + progress * 2.f - 1.5f; \
1032 for (int p = 0; p < s->nb_planes; p++) { \
1033 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1034 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1035 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1037 dst[x] = smooth >= 0.5f ? xf0[x] : xf1[x]; \
1046 #define PIXELIZE_TRANSITION(name, type, div) \
1047 static void pixelize##name##_transition(AVFilterContext *ctx, \
1048 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1050 int slice_start, int slice_end, int jobnr) \
1052 XFadeContext *s = ctx->priv; \
1053 const int w = out->width; \
1054 const int h = out->height; \
1055 const float d = fminf(progress, 1.f - progress); \
1056 const float dist = ceilf(d * 50.f) / 50.f; \
1057 const float sqx = 2.f * dist * FFMIN(w, h) / 20.f; \
1058 const float sqy = 2.f * dist * FFMIN(w, h) / 20.f; \
1060 for (int y = slice_start; y < slice_end; y++) { \
1061 for (int x = 0; x < w; x++) { \
1062 int sx = dist > 0.f ? FFMIN((floorf(x / sqx) + .5f) * sqx, w - 1) : x; \
1063 int sy = dist > 0.f ? FFMIN((floorf(y / sqy) + .5f) * sqy, h - 1) : y; \
1064 for (int p = 0; p < s->nb_planes; p++) { \
1065 const type *xf0 = (const type *)(a->data[p] + sy * a->linesize[p]); \
1066 const type *xf1 = (const type *)(b->data[p] + sy * b->linesize[p]); \
1067 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1069 dst[x] = mix(xf0[sx], xf1[sx], progress); \
1078 #define DIAGTL_TRANSITION(name, type, div) \
1079 static void diagtl##name##_transition(AVFilterContext *ctx, \
1080 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1082 int slice_start, int slice_end, int jobnr) \
1084 XFadeContext *s = ctx->priv; \
1085 const int width = out->width; \
1086 const float w = width; \
1087 const float h = out->height; \
1089 for (int y = slice_start; y < slice_end; y++) { \
1090 for (int x = 0; x < width; x++) { \
1091 const float smooth = 1.f + x / w * y / h - progress * 2.f; \
1093 for (int p = 0; p < s->nb_planes; p++) { \
1094 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1095 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1096 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1098 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1107 #define DIAGTR_TRANSITION(name, type, div) \
1108 static void diagtr##name##_transition(AVFilterContext *ctx, \
1109 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1111 int slice_start, int slice_end, int jobnr) \
1113 XFadeContext *s = ctx->priv; \
1114 const int width = out->width; \
1115 const float w = width; \
1116 const float h = out->height; \
1118 for (int y = slice_start; y < slice_end; y++) { \
1119 for (int x = 0; x < width; x++) { \
1120 const float smooth = 1.f + (w - 1 - x) / w * y / h - progress * 2.f; \
1122 for (int p = 0; p < s->nb_planes; p++) { \
1123 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1124 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1125 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1127 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1136 #define DIAGBL_TRANSITION(name, type, div) \
1137 static void diagbl##name##_transition(AVFilterContext *ctx, \
1138 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1140 int slice_start, int slice_end, int jobnr) \
1142 XFadeContext *s = ctx->priv; \
1143 const int width = out->width; \
1144 const float w = width; \
1145 const float h = out->height; \
1147 for (int y = slice_start; y < slice_end; y++) { \
1148 for (int x = 0; x < width; x++) { \
1149 const float smooth = 1.f + x / w * (h - 1 - y) / h - progress * 2.f; \
1151 for (int p = 0; p < s->nb_planes; p++) { \
1152 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1153 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1154 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1156 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1165 #define DIAGBR_TRANSITION(name, type, div) \
1166 static void diagbr##name##_transition(AVFilterContext *ctx, \
1167 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1169 int slice_start, int slice_end, int jobnr) \
1171 XFadeContext *s = ctx->priv; \
1172 const int width = out->width; \
1173 const float w = width; \
1174 const float h = out->height; \
1176 for (int y = slice_start; y < slice_end; y++) { \
1177 for (int x = 0; x < width; x++) { \
1178 const float smooth = 1.f + (w - 1 - x) / w * (h - 1 - y) / h - \
1181 for (int p = 0; p < s->nb_planes; p++) { \
1182 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1183 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1184 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1186 dst[x] = mix(xf1[x], xf0[x], smoothstep(0.f, 1.f, smooth)); \
1195 #define HLSLICE_TRANSITION(name, type, div) \
1196 static void hlslice##name##_transition(AVFilterContext *ctx, \
1197 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1199 int slice_start, int slice_end, int jobnr) \
1201 XFadeContext *s = ctx->priv; \
1202 const int width = out->width; \
1203 const float w = width; \
1205 for (int y = slice_start; y < slice_end; y++) { \
1206 for (int x = 0; x < width; x++) { \
1207 const float smooth = smoothstep(-0.5f, 0.f, x / w - progress * 1.5f); \
1208 const float ss = smooth <= fract(10.f * x / w) ? 0.f : 1.f; \
1210 for (int p = 0; p < s->nb_planes; p++) { \
1211 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1212 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1213 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1215 dst[x] = mix(xf1[x], xf0[x], ss); \
1224 #define HRSLICE_TRANSITION(name, type, div) \
1225 static void hrslice##name##_transition(AVFilterContext *ctx, \
1226 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1228 int slice_start, int slice_end, int jobnr) \
1230 XFadeContext *s = ctx->priv; \
1231 const int width = out->width; \
1232 const float w = width; \
1234 for (int y = slice_start; y < slice_end; y++) { \
1235 for (int x = 0; x < width; x++) { \
1236 const float xx = (w - 1 - x) / w; \
1237 const float smooth = smoothstep(-0.5f, 0.f, xx - progress * 1.5f); \
1238 const float ss = smooth <= fract(10.f * xx) ? 0.f : 1.f; \
1240 for (int p = 0; p < s->nb_planes; p++) { \
1241 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1242 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1243 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1245 dst[x] = mix(xf1[x], xf0[x], ss); \
1254 #define VUSLICE_TRANSITION(name, type, div) \
1255 static void vuslice##name##_transition(AVFilterContext *ctx, \
1256 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1258 int slice_start, int slice_end, int jobnr) \
1260 XFadeContext *s = ctx->priv; \
1261 const int width = out->width; \
1262 const float h = out->height; \
1264 for (int y = slice_start; y < slice_end; y++) { \
1265 const float smooth = smoothstep(-0.5f, 0.f, y / h - progress * 1.5f); \
1266 const float ss = smooth <= fract(10.f * y / h) ? 0.f : 1.f; \
1268 for (int x = 0; x < width; x++) { \
1269 for (int p = 0; p < s->nb_planes; p++) { \
1270 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1271 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1272 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1274 dst[x] = mix(xf1[x], xf0[x], ss); \
1283 #define VDSLICE_TRANSITION(name, type, div) \
1284 static void vdslice##name##_transition(AVFilterContext *ctx, \
1285 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1287 int slice_start, int slice_end, int jobnr) \
1289 XFadeContext *s = ctx->priv; \
1290 const int width = out->width; \
1291 const float h = out->height; \
1293 for (int y = slice_start; y < slice_end; y++) { \
1294 const float yy = (h - 1 - y) / h; \
1295 const float smooth = smoothstep(-0.5f, 0.f, yy - progress * 1.5f); \
1296 const float ss = smooth <= fract(10.f * yy) ? 0.f : 1.f; \
1298 for (int x = 0; x < width; x++) { \
1299 for (int p = 0; p < s->nb_planes; p++) { \
1300 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1301 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1302 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1304 dst[x] = mix(xf1[x], xf0[x], ss); \
1313 #define HBLUR_TRANSITION(name, type, div) \
1314 static void hblur##name##_transition(AVFilterContext *ctx, \
1315 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1317 int slice_start, int slice_end, int jobnr) \
1319 XFadeContext *s = ctx->priv; \
1320 const int width = out->width; \
1321 const float prog = progress <= 0.5f ? progress * 2.f : (1.f - progress) * 2.f; \
1322 const int size = 1 + (width / 2) * prog; \
1324 for (int y = slice_start; y < slice_end; y++) { \
1325 for (int p = 0; p < s->nb_planes; p++) { \
1326 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1327 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1328 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1333 for (int x = 0; x < size; x++) { \
1338 for (int x = 0; x < width; x++) { \
1339 dst[x] = mix(sum0 / cnt, sum1 / cnt, progress); \
1341 if (x + size < width) { \
1342 sum0 += xf0[x + size] - xf0[x]; \
1343 sum1 += xf1[x + size] - xf1[x]; \
1357 #define FADEGRAYS_TRANSITION(name, type, div) \
1358 static void fadegrays##name##_transition(AVFilterContext *ctx, \
1359 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1361 int slice_start, int slice_end, int jobnr) \
1363 XFadeContext *s = ctx->priv; \
1364 const int width = out->width; \
1365 const int is_rgb = s->is_rgb; \
1366 const int mid = (s->max_value + 1) / 2; \
1367 const float phase = 0.2f; \
1369 for (int y = slice_start; y < slice_end; y++) { \
1370 for (int x = 0; x < width; x++) { \
1373 for (int p = 0; p < s->nb_planes; p++) { \
1374 const type *xf0 = (const type *)(a->data[p] + \
1375 y * a->linesize[p]); \
1376 const type *xf1 = (const type *)(b->data[p] + \
1377 y * b->linesize[p]); \
1379 bg[0][3] = xf0[x]; \
1380 bg[1][3] = xf1[x]; \
1382 bg[0][0] += xf0[x]; \
1383 bg[1][0] += xf1[x]; \
1386 bg[0][0] = bg[0][0] / 3; \
1387 bg[1][0] = bg[1][0] / 3; \
1388 bg[0][1] = bg[0][2] = bg[0][0]; \
1389 bg[1][1] = bg[1][2] = bg[1][0]; \
1391 const type *yf0 = (const type *)(a->data[0] + \
1392 y * a->linesize[0]); \
1393 const type *yf1 = (const type *)(b->data[0] + \
1394 y * a->linesize[0]); \
1395 bg[0][0] = yf0[x]; \
1396 bg[1][0] = yf1[x]; \
1397 if (s->nb_planes == 4) { \
1398 const type *af0 = (const type *)(a->data[3] + \
1399 y * a->linesize[3]); \
1400 const type *af1 = (const type *)(b->data[3] + \
1401 y * a->linesize[3]); \
1402 bg[0][3] = af0[x]; \
1403 bg[1][3] = af1[x]; \
1405 bg[0][1] = bg[1][1] = mid; \
1406 bg[0][2] = bg[1][2] = mid; \
1409 for (int p = 0; p < s->nb_planes; p++) { \
1410 const type *xf0 = (const type *)(a->data[p] + y * a->linesize[p]); \
1411 const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
1412 type *dst = (type *)(out->data[p] + y * out->linesize[p]); \
1414 dst[x] = mix(mix(xf0[x], bg[0][p], \
1415 smoothstep(1.f-phase, 1.f, progress)), \
1416 mix(bg[1][p], xf1[x], smoothstep(phase, 1.f, progress)), \
1426 #define WIPETL_TRANSITION(name, type, div) \
1427 static void wipetl##name##_transition(AVFilterContext *ctx, \
1428 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1430 int slice_start, int slice_end, int jobnr) \
1432 XFadeContext *s = ctx->priv; \
1433 const int height = slice_end - slice_start; \
1434 const int zw = out->width * progress; \
1435 const int zh = out->height * progress; \
1437 for (int p = 0; p < s->nb_planes; p++) { \
1438 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1439 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1440 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1442 for (int y = 0; y < height; y++) { \
1443 for (int x = 0; x < out->width; x++) { \
1444 dst[x] = slice_start + y <= zh && \
1445 x <= zw ? xf0[x] : xf1[x]; \
1448 dst += out->linesize[p] / div; \
1449 xf0 += a->linesize[p] / div; \
1450 xf1 += b->linesize[p] / div; \
1458 #define WIPETR_TRANSITION(name, type, div) \
1459 static void wipetr##name##_transition(AVFilterContext *ctx, \
1460 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1462 int slice_start, int slice_end, int jobnr) \
1464 XFadeContext *s = ctx->priv; \
1465 const int height = slice_end - slice_start; \
1466 const int zw = out->width * (1.f - progress); \
1467 const int zh = out->height * progress; \
1469 for (int p = 0; p < s->nb_planes; p++) { \
1470 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1471 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1472 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1474 for (int y = 0; y < height; y++) { \
1475 for (int x = 0; x < out->width; x++) { \
1476 dst[x] = slice_start + y <= zh && \
1477 x > zw ? xf0[x] : xf1[x]; \
1480 dst += out->linesize[p] / div; \
1481 xf0 += a->linesize[p] / div; \
1482 xf1 += b->linesize[p] / div; \
1490 #define WIPEBL_TRANSITION(name, type, div) \
1491 static void wipebl##name##_transition(AVFilterContext *ctx, \
1492 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1494 int slice_start, int slice_end, int jobnr) \
1496 XFadeContext *s = ctx->priv; \
1497 const int height = slice_end - slice_start; \
1498 const int zw = out->width * progress; \
1499 const int zh = out->height * (1.f - progress); \
1501 for (int p = 0; p < s->nb_planes; p++) { \
1502 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1503 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1504 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1506 for (int y = 0; y < height; y++) { \
1507 for (int x = 0; x < out->width; x++) { \
1508 dst[x] = slice_start + y > zh && \
1509 x <= zw ? xf0[x] : xf1[x]; \
1512 dst += out->linesize[p] / div; \
1513 xf0 += a->linesize[p] / div; \
1514 xf1 += b->linesize[p] / div; \
1522 #define WIPEBR_TRANSITION(name, type, div) \
1523 static void wipebr##name##_transition(AVFilterContext *ctx, \
1524 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1526 int slice_start, int slice_end, int jobnr) \
1528 XFadeContext *s = ctx->priv; \
1529 const int height = slice_end - slice_start; \
1530 const int zh = out->height * (1.f - progress); \
1531 const int zw = out->width * (1.f - progress); \
1533 for (int p = 0; p < s->nb_planes; p++) { \
1534 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1535 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1536 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1538 for (int y = 0; y < height; y++) { \
1539 for (int x = 0; x < out->width; x++) { \
1540 dst[x] = slice_start + y > zh && \
1541 x > zw ? xf0[x] : xf1[x]; \
1544 dst += out->linesize[p] / div; \
1545 xf0 += a->linesize[p] / div; \
1546 xf1 += b->linesize[p] / div; \
1554 #define SQUEEZEH_TRANSITION(name, type, div) \
1555 static void squeezeh##name##_transition(AVFilterContext *ctx, \
1556 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1558 int slice_start, int slice_end, int jobnr) \
1560 XFadeContext *s = ctx->priv; \
1561 const float h = out->height; \
1562 const int height = slice_end - slice_start; \
1564 for (int p = 0; p < s->nb_planes; p++) { \
1565 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1566 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1568 for (int y = 0; y < height; y++) { \
1569 const float z = .5f + ((slice_start + y) / h - .5f) / progress; \
1571 if (z < 0.f || z > 1.f) { \
1572 for (int x = 0; x < out->width; x++) \
1575 const int yy = lrintf(z * (h - 1.f)); \
1576 const type *xf0 = (const type *)(a->data[p] + yy * a->linesize[p]); \
1578 for (int x = 0; x < out->width; x++) \
1582 dst += out->linesize[p] / div; \
1583 xf1 += b->linesize[p] / div; \
1591 #define SQUEEZEV_TRANSITION(name, type, div) \
1592 static void squeezev##name##_transition(AVFilterContext *ctx, \
1593 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1595 int slice_start, int slice_end, int jobnr) \
1597 XFadeContext *s = ctx->priv; \
1598 const float w = out->width; \
1599 const int height = slice_end - slice_start; \
1601 for (int p = 0; p < s->nb_planes; p++) { \
1602 const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
1603 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1604 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1606 for (int y = 0; y < height; y++) { \
1607 for (int x = 0; x < out->width; x++) { \
1608 const float z = .5f + (x / w - .5f) / progress; \
1610 if (z < 0.f || z > 1.f) { \
1613 const int xx = lrintf(z * (w - 1.f)); \
1619 dst += out->linesize[p] / div; \
1620 xf0 += a->linesize[p] / div; \
1621 xf1 += b->linesize[p] / div; \
1629 static
void zoom(
float *
u,
float *v,
float amount)
1631 *
u = 0.5f + ((*
u - 0.5f) * amount);
1632 *v = 0.5f + ((*v - 0.5f) * amount);
1635 #define ZOOMIN_TRANSITION(name, type, div) \
1636 static void zoomin##name##_transition(AVFilterContext *ctx, \
1637 const AVFrame *a, const AVFrame *b, AVFrame *out, \
1639 int slice_start, int slice_end, int jobnr) \
1641 XFadeContext *s = ctx->priv; \
1642 const float w = out->width; \
1643 const float h = out->height; \
1644 const float zf = smoothstep(0.5f, 1.f, progress); \
1646 for (int p = 0; p < s->nb_planes; p++) { \
1647 const type *xf0 = (const type *)(a->data[p]); \
1648 const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
1649 type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]); \
1651 for (int y = slice_start; y < slice_end; y++) { \
1652 for (int x = 0; x < w; x++) { \
1659 iu = ceilf(u * (w - 1)); \
1660 iv = ceilf(v * (h - 1)); \
1661 zv = xf0[iu + iv * a->linesize[p] / div]; \
1662 dst[x] = mix(zv, xf1[x], smoothstep(0.f, 0.5f, progress)); \
1664 dst += out->linesize[p] / div; \
1665 xf1 += b->linesize[p] / div; \
1673 static inline
double getpix(
void *priv,
double x,
double y,
int plane,
int nb)
1677 const uint8_t *
src = in->
data[
FFMIN(plane,
s->nb_planes - 1)];
1688 const uint16_t *src16 = (
const uint16_t*)
src;
1691 return src16[
xi + yi * linesize];
1693 return src[
xi + yi * linesize];
1697 static double a0(
void *priv,
double x,
double y) {
return getpix(priv, x, y, 0, 0); }
1698 static double a1(
void *priv,
double x,
double y) {
return getpix(priv, x, y, 1, 0); }
1699 static double a2(
void *priv,
double x,
double y) {
return getpix(priv, x, y, 2, 0); }
1700 static double a3(
void *priv,
double x,
double y) {
return getpix(priv, x, y, 3, 0); }
1702 static double b0(
void *priv,
double x,
double y) {
return getpix(priv, x, y, 0, 1); }
1703 static double b1(
void *priv,
double x,
double y) {
return getpix(priv, x, y, 1, 1); }
1704 static double b2(
void *priv,
double x,
double y) {
return getpix(priv, x, y, 2, 1); }
1705 static double b3(
void *priv,
double x,
double y) {
return getpix(priv, x, y, 3, 1); }
1715 if (inlink0->
w != inlink1->
w || inlink0->
h != inlink1->
h) {
1717 "(size %dx%d) do not match the corresponding "
1718 "second input link %s parameters (size %dx%d)\n",
1719 ctx->input_pads[0].name, inlink0->
w, inlink0->
h,
1720 ctx->input_pads[1].name, inlink1->
w, inlink1->
h);
1727 "(%d/%d) do not match the corresponding "
1728 "second input link %s timebase (%d/%d)\n",
1743 "(%d/%d) do not match the corresponding "
1744 "second input link %s frame rate (%d/%d)\n",
1750 outlink->
w = inlink0->
w;
1751 outlink->
h = inlink0->
h;
1759 s->max_value = (1 <<
s->depth) - 1;
1761 s->black[1] =
s->black[2] =
s->is_rgb ? 0 :
s->max_value / 2;
1762 s->black[3] =
s->max_value;
1763 s->white[0] =
s->white[3] =
s->max_value;
1764 s->white[1] =
s->white[2] =
s->is_rgb ?
s->max_value :
s->max_value / 2;
1773 switch (
s->transition) {
1774 case CUSTOM:
s->transitionf =
s->depth <= 8 ? custom8_transition : custom16_transition;
break;
1775 case FADE:
s->transitionf =
s->depth <= 8 ? fade8_transition : fade16_transition;
break;
1776 case WIPELEFT:
s->transitionf =
s->depth <= 8 ? wipeleft8_transition : wipeleft16_transition;
break;
1777 case WIPERIGHT:
s->transitionf =
s->depth <= 8 ? wiperight8_transition : wiperight16_transition;
break;
1778 case WIPEUP:
s->transitionf =
s->depth <= 8 ? wipeup8_transition : wipeup16_transition;
break;
1779 case WIPEDOWN:
s->transitionf =
s->depth <= 8 ? wipedown8_transition : wipedown16_transition;
break;
1780 case SLIDELEFT:
s->transitionf =
s->depth <= 8 ? slideleft8_transition : slideleft16_transition;
break;
1781 case SLIDERIGHT:
s->transitionf =
s->depth <= 8 ? slideright8_transition : slideright16_transition;
break;
1782 case SLIDEUP:
s->transitionf =
s->depth <= 8 ? slideup8_transition : slideup16_transition;
break;
1783 case SLIDEDOWN:
s->transitionf =
s->depth <= 8 ? slidedown8_transition : slidedown16_transition;
break;
1784 case CIRCLECROP:
s->transitionf =
s->depth <= 8 ? circlecrop8_transition : circlecrop16_transition;
break;
1785 case RECTCROP:
s->transitionf =
s->depth <= 8 ? rectcrop8_transition : rectcrop16_transition;
break;
1786 case DISTANCE:
s->transitionf =
s->depth <= 8 ? distance8_transition : distance16_transition;
break;
1787 case FADEBLACK:
s->transitionf =
s->depth <= 8 ? fadeblack8_transition : fadeblack16_transition;
break;
1788 case FADEWHITE:
s->transitionf =
s->depth <= 8 ? fadewhite8_transition : fadewhite16_transition;
break;
1789 case RADIAL:
s->transitionf =
s->depth <= 8 ? radial8_transition : radial16_transition;
break;
1790 case SMOOTHLEFT:
s->transitionf =
s->depth <= 8 ? smoothleft8_transition : smoothleft16_transition;
break;
1791 case SMOOTHRIGHT:
s->transitionf =
s->depth <= 8 ? smoothright8_transition: smoothright16_transition;
break;
1792 case SMOOTHUP:
s->transitionf =
s->depth <= 8 ? smoothup8_transition : smoothup16_transition;
break;
1793 case SMOOTHDOWN:
s->transitionf =
s->depth <= 8 ? smoothdown8_transition : smoothdown16_transition;
break;
1794 case CIRCLEOPEN:
s->transitionf =
s->depth <= 8 ? circleopen8_transition : circleopen16_transition;
break;
1795 case CIRCLECLOSE:
s->transitionf =
s->depth <= 8 ? circleclose8_transition: circleclose16_transition;
break;
1796 case VERTOPEN:
s->transitionf =
s->depth <= 8 ? vertopen8_transition : vertopen16_transition;
break;
1797 case VERTCLOSE:
s->transitionf =
s->depth <= 8 ? vertclose8_transition : vertclose16_transition;
break;
1798 case HORZOPEN:
s->transitionf =
s->depth <= 8 ? horzopen8_transition : horzopen16_transition;
break;
1799 case HORZCLOSE:
s->transitionf =
s->depth <= 8 ? horzclose8_transition : horzclose16_transition;
break;
1800 case DISSOLVE:
s->transitionf =
s->depth <= 8 ? dissolve8_transition : dissolve16_transition;
break;
1801 case PIXELIZE:
s->transitionf =
s->depth <= 8 ? pixelize8_transition : pixelize16_transition;
break;
1802 case DIAGTL:
s->transitionf =
s->depth <= 8 ? diagtl8_transition : diagtl16_transition;
break;
1803 case DIAGTR:
s->transitionf =
s->depth <= 8 ? diagtr8_transition : diagtr16_transition;
break;
1804 case DIAGBL:
s->transitionf =
s->depth <= 8 ? diagbl8_transition : diagbl16_transition;
break;
1805 case DIAGBR:
s->transitionf =
s->depth <= 8 ? diagbr8_transition : diagbr16_transition;
break;
1806 case HLSLICE:
s->transitionf =
s->depth <= 8 ? hlslice8_transition : hlslice16_transition;
break;
1807 case HRSLICE:
s->transitionf =
s->depth <= 8 ? hrslice8_transition : hrslice16_transition;
break;
1808 case VUSLICE:
s->transitionf =
s->depth <= 8 ? vuslice8_transition : vuslice16_transition;
break;
1809 case VDSLICE:
s->transitionf =
s->depth <= 8 ? vdslice8_transition : vdslice16_transition;
break;
1810 case HBLUR:
s->transitionf =
s->depth <= 8 ? hblur8_transition : hblur16_transition;
break;
1811 case FADEGRAYS:
s->transitionf =
s->depth <= 8 ? fadegrays8_transition : fadegrays16_transition;
break;
1812 case WIPETL:
s->transitionf =
s->depth <= 8 ? wipetl8_transition : wipetl16_transition;
break;
1813 case WIPETR:
s->transitionf =
s->depth <= 8 ? wipetr8_transition : wipetr16_transition;
break;
1814 case WIPEBL:
s->transitionf =
s->depth <= 8 ? wipebl8_transition : wipebl16_transition;
break;
1815 case WIPEBR:
s->transitionf =
s->depth <= 8 ? wipebr8_transition : wipebr16_transition;
break;
1816 case SQUEEZEH:
s->transitionf =
s->depth <= 8 ? squeezeh8_transition : squeezeh16_transition;
break;
1817 case SQUEEZEV:
s->transitionf =
s->depth <= 8 ? squeezev8_transition : squeezev16_transition;
break;
1818 case ZOOMIN:
s->transitionf =
s->depth <= 8 ? zoomin8_transition : zoomin16_transition;
break;
1822 if (
s->transition ==
CUSTOM) {
1824 "a0",
"a1",
"a2",
"a3",
1825 "b0",
"b1",
"b2",
"b3",
1828 double (*
func2[])(
void *, double, double) = {
1850 int slice_start = (outlink->
h * jobnr ) / nb_jobs;
1851 int slice_end = (outlink->
h * (jobnr+1)) / nb_jobs;
1862 float progress =
av_clipf(1.
f - ((
float)(
s->pts -
s->first_pts -
s->offset_pts) /
s->duration_pts), 0.f, 1.f);
1871 td.xf[0] =
a,
td.xf[1] =
b,
td.out =
out,
td.progress = progress;
1890 if (
s->xfade_is_over) {
1899 }
else if (
ret > 0) {
1900 in->
pts = (in->
pts -
s->last_pts) +
s->pts;
1916 s->first_pts =
s->xf[0]->pts;
1918 s->pts =
s->xf[0]->pts;
1919 if (
s->first_pts +
s->offset_pts >
s->xf[0]->pts) {
1934 s->last_pts =
s->xf[1]->pts;
1935 s->pts =
s->xf[0]->pts;
1936 if (
s->xf[0]->pts - (
s->first_pts +
s->offset_pts) >
s->duration_pts)
1937 s->xfade_is_over = 1;
1953 s->xfade_is_over = 1;
1962 if (
s->eof[0] &&
s->eof[1] && (
1966 }
else if (
s->xfade_is_over) {
1998 .priv_class = &xfade_class,
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
static enum AVPixelFormat pix_fmts[]
#define AV_PIX_FMT_GBRAP16
AVPixelFormat
Pixel format.
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
#define HORZOPEN_TRANSITION(name, type, div)
#define FADEBLACK_TRANSITION(name, type, div)
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
#define SLIDERIGHT_TRANSITION(name, type, div)
static int xfade_activate(AVFilterContext *ctx)
#define CIRCLECROP_TRANSITION(name, type, div)
#define u(width, name, range_min, range_max)
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
#define AVERROR_EOF
End of file.
static const AVOption xfade_options[]
#define FILTER_PIXFMTS_ARRAY(array)
static __device__ float floorf(float a)
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
#define WIPEDOWN_TRANSITION(name, type, div)
static void zoom(float *u, float *v, float amount)
#define RECTCROP_TRANSITION(name, type, div)
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
AVFILTER_DEFINE_CLASS(xfade)
#define WIPEBL_TRANSITION(name, type, div)
This structure describes decoded (raw) audio or video data.
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
#define SLIDELEFT_TRANSITION(name, type, div)
int depth
Number of bits in the component.
#define VDSLICE_TRANSITION(name, type, div)
#define WIPERIGHT_TRANSITION(name, type, div)
const char * name
Filter name.
#define SMOOTHDOWN_TRANSITION(name, type, div)
A link between two filters.
static float mix(float a, float b, float mix)
static const char *const func2_names[]
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
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.
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
#define FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, filter)
Forward the status on an output link to all input links.
#define AV_PIX_FMT_GBRP14
static double b1(void *priv, double x, double y)
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
#define AV_PIX_FMT_GBRP10
#define AV_PIX_FMT_YUVA444P16
#define VERTOPEN_TRANSITION(name, type, div)
static int xfade_frame(AVFilterContext *ctx, AVFrame *a, AVFrame *b)
#define FADEGRAYS_TRANSITION(name, type, div)
#define SLIDEDOWN_TRANSITION(name, type, div)
#define PIXELIZE_TRANSITION(name, type, div)
#define AV_PIX_FMT_GRAY16
static double a2(void *priv, double x, double y)
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
#define HLSLICE_TRANSITION(name, type, div)
A filter pad used for either input or output.
#define AV_PIX_FMT_YUV444P10
static double(*const func2[])(void *, double, double)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
#define DIAGTR_TRANSITION(name, type, div)
#define SMOOTHLEFT_TRANSITION(name, type, div)
#define AV_PIX_FMT_GBRAP10
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
static double b3(void *priv, double x, double y)
#define ZOOMIN_TRANSITION(name, type, div)
#define AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_YUV444P16
static float smoothstep(float edge0, float edge1, float x)
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
AVRational sample_aspect_ratio
agreed upon sample aspect ratio
static const char *const var_names[]
AVRational frame_rate
Frame rate of the stream on the link, or 1/0 if unknown or variable; if left to 0/0,...
#define AV_PIX_FMT_YUVA444P12
#define xi(width, name, var, range_min, range_max, subs,...)
static double getpix(void *priv, double x, double y, int plane, int nb)
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
#define CIRCLECLOSE_TRANSITION(name, type, div)
#define DIAGBL_TRANSITION(name, type, div)
#define FILTER_INPUTS(array)
#define WIPETR_TRANSITION(name, type, div)
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
#define AV_PIX_FMT_GRAY10
AVFrame * ff_inlink_peek_frame(AVFilterLink *link, size_t idx)
Access a frame in the link fifo without consuming it.
#define AV_PIX_FMT_GBRP16
#define SLIDEUP_TRANSITION(name, type, div)
Describe the class of an AVClass context structure.
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
static double a3(void *priv, double x, double y)
#define FADE_TRANSITION(name, type, div)
filter_frame For filters that do not use the activate() callback
static const AVFilterPad xfade_inputs[]
const AVFilter ff_vf_xfade
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
#define DISTANCE_TRANSITION(name, type, div)
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
static const AVFilterPad xfade_outputs[]
size_t ff_inlink_queued_frames(AVFilterLink *link)
Get the number of frames available on the link.
#define RADIAL_TRANSITION(name, type, div)
#define WIPELEFT_TRANSITION(name, type, div)
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
#define CUSTOM_TRANSITION(name, type, div)
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
#define HORZCLOSE_TRANSITION(name, type, div)
int format
agreed upon media format
static av_cold void uninit(AVFilterContext *ctx)
#define AV_NOPTS_VALUE
Undefined timestamp value.
#define HBLUR_TRANSITION(name, type, div)
#define AV_PIX_FMT_YUV444P12
AVFilterContext * src
source filter
#define VUSLICE_TRANSITION(name, type, div)
static double b2(void *priv, double x, double y)
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
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
static double a0(void *priv, double x, double y)
#define AV_PIX_FMT_YUVA444P10
static float frand(int x, int y)
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
#define WIPEUP_TRANSITION(name, type, div)
static int config_output(AVFilterLink *outlink)
#define SMOOTHRIGHT_TRANSITION(name, type, div)
int w
agreed upon image width
#define AV_PIX_FMT_GBRP12
#define VERTCLOSE_TRANSITION(name, type, div)
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Used for passing data between threads.
#define WIPETL_TRANSITION(name, type, div)
#define DIAGTL_TRANSITION(name, type, div)
const char * name
Pad name.
static float fract(float a)
#define SQUEEZEH_TRANSITION(name, type, div)
#define CIRCLEOPEN_TRANSITION(name, type, div)
#define AV_PIX_FMT_YUVA444P9
#define SQUEEZEV_TRANSITION(name, type, div)
static int xfade_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
int h
agreed upon image height
#define FADEWHITE_TRANSITION(name, type, div)
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
AVRational time_base
Define the time base used by the PTS of the frames/samples which will pass through this link.
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
int ff_outlink_get_status(AVFilterLink *link)
Get the status on an output link.
#define SMOOTHUP_TRANSITION(name, type, div)
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
void(* transitionf)(AVFilterContext *ctx, const AVFrame *a, const AVFrame *b, AVFrame *out, float progress, int slice_start, int slice_end, int jobnr)
#define FILTER_OUTPUTS(array)
#define DIAGBR_TRANSITION(name, type, div)
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
static double b0(void *priv, double x, double y)
static double a1(void *priv, double x, double y)
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_PIX_FMT_YUV444P14
#define AV_PIX_FMT_GRAY12
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
#define WIPEBR_TRANSITION(name, type, div)
#define DISSOLVE_TRANSITION(name, type, div)
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.
#define HRSLICE_TRANSITION(name, type, div)