-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathvf_xfade.patch
More file actions
145 lines (134 loc) · 8.88 KB
/
vf_xfade.patch
File metadata and controls
145 lines (134 loc) · 8.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
--- libavfilter/vf_xfade.c 2026-03-22 12:13:52
+++ vf_xfade.c 2026-03-22 12:13:52
@@ -126,6 +126,11 @@
void (*transitionf)(AVFilterContext *ctx, const AVFrame *a, const AVFrame *b, AVFrame *out, float progress,
int slice_start, int slice_end, int jobnr);
+ char *easing_str; // easing name with optional args
+ char *transition_str; // transition name with optional args
+ int reverse; // reverse option bit flags (enum ReverseFlags)
+ struct XFadeEasingContext *k; // xfade-easing data
+
AVExpr *e;
} XFadeContext;
@@ -157,18 +162,22 @@
AV_PIX_FMT_NONE
};
+static void xe_data_free(struct XFadeEasingContext *k);
static av_cold void uninit(AVFilterContext *ctx)
{
XFadeContext *s = ctx->priv;
av_expr_free(s->e);
+ xe_data_free(s->k);
}
#define OFFSET(x) offsetof(XFadeContext, x)
#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
static const AVOption xfade_options[] = {
- { "transition", "set cross fade transition", OFFSET(transition), AV_OPT_TYPE_INT, {.i64=FADE}, -1, NB_TRANSITIONS-1, FLAGS, .unit = "transition" },
+ { "easing", "set cross fade easing", OFFSET(easing_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
+ { "reverse", "reverse easing/transition", OFFSET(reverse), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, FLAGS },
+ { "transition", "set cross fade transition", OFFSET(transition_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS, .unit = "transition" },
{ "custom", "custom transition", 0, AV_OPT_TYPE_CONST, {.i64=CUSTOM}, 0, 0, FLAGS, .unit = "transition" },
{ "fade", "fade transition", 0, AV_OPT_TYPE_CONST, {.i64=FADE}, 0, 0, FLAGS, .unit = "transition" },
{ "wipeleft", "wipe left transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPELEFT}, 0, 0, FLAGS, .unit = "transition" },
@@ -469,7 +478,7 @@
for (int y = 0; y < height; y++) { \
for (int x = 0; x < width; x++) { \
const int zx = z + x; \
- const int zz = zx % width + width * (zx < 0); \
+ const int zz = zx % width + width * (zx < 0 && zx > -width); \
dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz]; \
} \
\
@@ -502,7 +511,7 @@
for (int y = 0; y < height; y++) { \
for (int x = 0; x < width; x++) { \
const int zx = z + x; \
- const int zz = zx % width + width * (zx < 0); \
+ const int zz = zx % width; \
dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz]; \
} \
\
@@ -532,7 +541,7 @@
\
for (int y = slice_start; y < slice_end; y++) { \
const int zy = z + y; \
- const int zz = zy % height + height * (zy < 0); \
+ const int zz = zy % height + height * (zy < 0 && zy > -height); \
const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \
\
@@ -564,7 +573,7 @@
\
for (int y = slice_start; y < slice_end; y++) { \
const int zy = z + y; \
- const int zz = zy % height + height * (zy < 0); \
+ const int zz = zy % height; \
const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \
\
@@ -1633,7 +1642,7 @@
for (int y = 0; y < height; y++) { \
const float z = .5f + ((slice_start + y) / h - .5f) / progress; \
\
- if (z < 0.f || z > 1.f) { \
+ if (z < 0.f || z > 1.f || progress <= 0.f) { \
for (int x = 0; x < width; x++) \
dst[x] = xf1[x]; \
} else { \
@@ -1673,7 +1682,7 @@
for (int x = 0; x < width; x++) { \
const float z = .5f + (x / w - .5f) / progress; \
\
- if (z < 0.f || z > 1.f) { \
+ if (z < 0.f || z > 1.f || progress <= 0.f) { \
dst[x] = xf1[x]; \
} else { \
const int xx = lrintf(z * (w - 1.f)); \
@@ -1952,7 +1961,7 @@
for (int y = 0; y < height; y++) { \
for (int x = 0; x < width; x++) { \
const int zx = z + x; \
- const int zz = zx % width + width * (zx < 0); \
+ const int zz = zx % width + width * (zx < 0 && zx > -width); \
dst[x] = (zx >= 0) && (zx < width) ? xf1[x] : xf0[zz]; \
} \
\
@@ -1984,7 +1993,7 @@
\
for (int y = slice_start; y < slice_end; y++) { \
const int zy = z + y; \
- const int zz = zy % height + height * (zy < 0); \
+ const int zz = zy % height + height * (zy < 0 && zy > -height); \
const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \
const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \
\
@@ -2001,6 +2010,8 @@
REVEALV_TRANSITION(down, 8, uint8_t, 1, )
REVEALV_TRANSITION(down, 16, uint16_t, 2, )
+#include "xfade-easing.h" // easing & extended transitions
+
static inline double getpix(void *priv, double x, double y, int plane, int nb)
{
XFadeContext *s = priv;
@@ -2101,6 +2112,9 @@
if (s->duration)
s->duration_pts = av_rescale_q(s->duration, AV_TIME_BASE_Q, outlink->time_base);
+
+ int ret = config_xfade_easing(ctx);
+ if (ret <= 0) return ret; // error or extended transition
switch (s->transition) {
case CUSTOM: s->transitionf = s->depth <= 8 ? custom8_transition : custom16_transition; break;
@@ -2214,7 +2228,14 @@
return AVERROR(ENOMEM);
av_frame_copy_props(out, a);
- td.xf[0] = a, td.xf[1] = b, td.out = out, td.progress = progress;
+ progress = (s->reverse & REVERSE_EASING) ? 1 - ease(s, 1 - progress) : ease(s, progress); // eased progress
+ int i = s->reverse & REVERSE_TRANSITION;
+ if (i) progress = 1 - progress;
+ if (s->reverse & REVERSE_OVERSHOOT) { // internal flag
+ if (progress < 0) progress += 1, i ^= 1; // undershoot
+ else if (progress > 1) progress -= 1, i ^= 1; // overshoot
+ }
+ td.xf[i] = a, td.xf[i ^ 1] = b, td.out = out, td.progress = av_clipf(progress, 0, 1);
ff_filter_execute(ctx, xfade_slice, &td, NULL,
FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));