| Original vf_xfade.c |
Amended vf_xfade.c |
|
126: void (*transitionf)(AVFilterContext *ctx, const AVFrame *a, const AVFrame *b, AVFrame *out, float progress, |
126: void (*transitionf)(AVFilterContext *ctx, const AVFrame *a, const AVFrame *b, AVFrame *out, float progress, |
|
127: int slice_start, int slice_end, int jobnr); |
127: int slice_start, int slice_end, int jobnr); |
| 128: |
128: |
| |
129: char *easing_str; // easing name with optional args |
| |
130: char *transition_str; // transition name with optional args |
| |
131: int reverse; // reverse option bit flags (enum ReverseFlags) |
| |
132: struct XFadeEasingContext *k; // xfade-easing data |
| |
133: |
| 129: AVExpr *e; |
134: AVExpr *e; |
| 130: } XFadeContext; |
135: } XFadeContext; |
| 131: |
136: |
| 157: AV_PIX_FMT_NONE |
162: AV_PIX_FMT_NONE |
| 158: }; |
163: }; |
| 159: |
164: |
| |
165: static void xe_data_free(struct XFadeEasingContext *k); |
| 160: static av_cold void uninit(AVFilterContext *ctx) |
166: static av_cold void uninit(AVFilterContext *ctx) |
| 161: { |
167: { |
| 162: XFadeContext *s = ctx->priv; |
168: XFadeContext *s = ctx->priv; |
| 163: |
169: |
| 164: av_expr_free(s->e); |
170: av_expr_free(s->e); |
| |
171: xe_data_free(s->k); |
| 165: } |
172: } |
| 166: |
173: |
| 167: #define OFFSET(x) offsetof(XFadeContext, x) |
174: #define OFFSET(x) offsetof(XFadeContext, x) |
|
168: #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) |
175: #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) |
| 169: |
176: |
| 170: static const AVOption xfade_options[] = { |
177: static const AVOption xfade_options[] = { |
|
171: { "transition", "set cross fade transition", OFFSET(transition), AV_OPT_TYPE_INT, {.i64=FADE}, -1, NB_TRANSITIONS-1, FLAGS, .unit = "transition" }, |
178: { "easing", "set cross fade easing", OFFSET(easing_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, |
| |
179: { "reverse", "reverse easing/transition", OFFSET(reverse), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, FLAGS }, |
| |
180: { "transition", "set cross fade transition", OFFSET(transition_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS, .unit = "transition" }, |
|
172: { "custom", "custom transition", 0, AV_OPT_TYPE_CONST, {.i64=CUSTOM}, 0, 0, FLAGS, .unit = "transition" }, |
181: { "custom", "custom transition", 0, AV_OPT_TYPE_CONST, {.i64=CUSTOM}, 0, 0, FLAGS, .unit = "transition" }, |
|
173: { "fade", "fade transition", 0, AV_OPT_TYPE_CONST, {.i64=FADE}, 0, 0, FLAGS, .unit = "transition" }, |
182: { "fade", "fade transition", 0, AV_OPT_TYPE_CONST, {.i64=FADE}, 0, 0, FLAGS, .unit = "transition" }, |
|
174: { "wipeleft", "wipe left transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPELEFT}, 0, 0, FLAGS, .unit = "transition" }, |
183: { "wipeleft", "wipe left transition", 0, AV_OPT_TYPE_CONST, {.i64=WIPELEFT}, 0, 0, FLAGS, .unit = "transition" }, |
|
469: for (int y = 0; y < height; y++) { \ |
478: for (int y = 0; y < height; y++) { \ |
|
470: for (int x = 0; x < width; x++) { \ |
479: for (int x = 0; x < width; x++) { \ |
|
471: const int zx = z + x; \ |
480: const int zx = z + x; \ |
|
472: const int zz = zx % width + width * (zx < 0); \ |
481: const int zz = zx % width + width * (zx < 0 && zx > -width); \ |
|
473: dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz]; \ |
482: dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz]; \ |
|
474: } \ |
483: } \ |
|
475: \ |
484: \ |
|
502: for (int y = 0; y < height; y++) { \ |
511: for (int y = 0; y < height; y++) { \ |
|
503: for (int x = 0; x < width; x++) { \ |
512: for (int x = 0; x < width; x++) { \ |
|
504: const int zx = z + x; \ |
513: const int zx = z + x; \ |
|
505: const int zz = zx % width + width * (zx < 0); \ |
514: const int zz = zx % width; \ |
|
506: dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz]; \ |
515: dst[x] = (zx >= 0) && (zx < width) ? xf1[zz] : xf0[zz]; \ |
|
507: } \ |
516: } \ |
|
508: \ |
517: \ |
|
532: \ |
541: \ |
|
533: for (int y = slice_start; y < slice_end; y++) { \ |
542: for (int y = slice_start; y < slice_end; y++) { \ |
|
534: const int zy = z + y; \ |
543: const int zy = z + y; \ |
|
535: const int zz = zy % height + height * (zy < 0); \ |
544: const int zz = zy % height + height * (zy < 0 && zy > -height); \ |
|
536: const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \ |
545: const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \ |
|
537: const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \ |
546: const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \ |
|
538: \ |
547: \ |
|
564: \ |
573: \ |
|
565: for (int y = slice_start; y < slice_end; y++) { \ |
574: for (int y = slice_start; y < slice_end; y++) { \ |
|
566: const int zy = z + y; \ |
575: const int zy = z + y; \ |
|
567: const int zz = zy % height + height * (zy < 0); \ |
576: const int zz = zy % height; \ |
|
568: const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \ |
577: const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \ |
|
569: const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \ |
578: const type *xf1 = (const type *)(b->data[p] + zz * b->linesize[p]); \ |
|
570: \ |
579: \ |
|
1633: for (int y = 0; y < height; y++) { \ |
1642: for (int y = 0; y < height; y++) { \ |
|
1634: const float z = .5f + ((slice_start + y) / h - .5f) / progress; \ |
1643: const float z = .5f + ((slice_start + y) / h - .5f) / progress; \ |
|
1635: \ |
1644: \ |
|
1636: if (z < 0.f || z > 1.f) { \ |
1645: if (z < 0.f || z > 1.f || progress <= 0.f) { \ |
|
1637: for (int x = 0; x < width; x++) \ |
1646: for (int x = 0; x < width; x++) \ |
|
1638: dst[x] = xf1[x]; \ |
1647: dst[x] = xf1[x]; \ |
|
1639: } else { \ |
1648: } else { \ |
|
1673: for (int x = 0; x < width; x++) { \ |
1682: for (int x = 0; x < width; x++) { \ |
|
1674: const float z = .5f + (x / w - .5f) / progress; \ |
1683: const float z = .5f + (x / w - .5f) / progress; \ |
|
1675: \ |
1684: \ |
|
1676: if (z < 0.f || z > 1.f) { \ |
1685: if (z < 0.f || z > 1.f || progress <= 0.f) { \ |
|
1677: dst[x] = xf1[x]; \ |
1686: dst[x] = xf1[x]; \ |
|
1678: } else { \ |
1687: } else { \ |
|
1679: const int xx = lrintf(z * (w - 1.f)); \ |
1688: const int xx = lrintf(z * (w - 1.f)); \ |
|
1952: for (int y = 0; y < height; y++) { \ |
1961: for (int y = 0; y < height; y++) { \ |
|
1953: for (int x = 0; x < width; x++) { \ |
1962: for (int x = 0; x < width; x++) { \ |
|
1954: const int zx = z + x; \ |
1963: const int zx = z + x; \ |
|
1955: const int zz = zx % width + width * (zx < 0); \ |
1964: const int zz = zx % width + width * (zx < 0 && zx > -width); \ |
|
1956: dst[x] = (zx >= 0) && (zx < width) ? xf1[x] : xf0[zz]; \ |
1965: dst[x] = (zx >= 0) && (zx < width) ? xf1[x] : xf0[zz]; \ |
|
1957: } \ |
1966: } \ |
|
1958: \ |
1967: \ |
|
1984: \ |
1993: \ |
|
1985: for (int y = slice_start; y < slice_end; y++) { \ |
1994: for (int y = slice_start; y < slice_end; y++) { \ |
|
1986: const int zy = z + y; \ |
1995: const int zy = z + y; \ |
|
1987: const int zz = zy % height + height * (zy < 0); \ |
1996: const int zz = zy % height + height * (zy < 0 && zy > -height); \ |
|
1988: const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \ |
1997: const type *xf0 = (const type *)(a->data[p] + zz * a->linesize[p]); \ |
|
1989: const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \ |
1998: const type *xf1 = (const type *)(b->data[p] + y * b->linesize[p]); \ |
|
1990: \ |
1999: \ |
| 2001: REVEALV_TRANSITION(down, 8, uint8_t, 1, ) |
2010: REVEALV_TRANSITION(down, 8, uint8_t, 1, ) |
| 2002: REVEALV_TRANSITION(down, 16, uint16_t, 2, ) |
2011: REVEALV_TRANSITION(down, 16, uint16_t, 2, ) |
| 2003: |
2012: |
| |
2013: #include "xfade-easing.h" // easing & extended transitions |
| |
2014: |
|
2004: static inline double getpix(void *priv, double x, double y, int plane, int nb) |
2015: static inline double getpix(void *priv, double x, double y, int plane, int nb) |
| 2005: { |
2016: { |
| 2006: XFadeContext *s = priv; |
2017: XFadeContext *s = priv; |
| 2101: |
2112: |
| 2102: if (s->duration) |
2113: if (s->duration) |
|
2103: s->duration_pts = av_rescale_q(s->duration, AV_TIME_BASE_Q, outlink->time_base); |
2114: s->duration_pts = av_rescale_q(s->duration, AV_TIME_BASE_Q, outlink->time_base); |
| |
2115: |
| |
2116: int ret = config_xfade_easing(ctx); |
| |
2117: if (ret <= 0) return ret; // error or extended transition |
| 2104: |
2118: |
| 2105: switch (s->transition) { |
2119: switch (s->transition) { |
|
2106: case CUSTOM: s->transitionf = s->depth <= 8 ? custom8_transition : custom16_transition; break; |
2120: case CUSTOM: s->transitionf = s->depth <= 8 ? custom8_transition : custom16_transition; break; |
|
2214: return AVERROR(ENOMEM); |
2228: return AVERROR(ENOMEM); |
| 2215: av_frame_copy_props(out, a); |
2229: av_frame_copy_props(out, a); |
| 2216: |
2230: |
|
2217: td.xf[0] = a, td.xf[1] = b, td.out = out, td.progress = progress; |
2231: progress = (s->reverse & REVERSE_EASING) ? 1 - ease(s, 1 - progress) : ease(s, progress); // eased progress |
| |
2232: int i = s->reverse & REVERSE_TRANSITION; |
| |
2233: if (i) progress = 1 - progress; |
| |
2234: if (s->reverse & REVERSE_OVERSHOOT) { // internal flag |
| |
2235: if (progress < 0) progress += 1, i ^= 1; // undershoot |
| |
2236: else if (progress > 1) progress -= 1, i ^= 1; // overshoot |
| |
2237: } |
| |
2238: td.xf[i] = a, td.xf[i ^ 1] = b, td.out = out, td.progress = av_clipf(progress, 0, 1); |
|
2218: ff_filter_execute(ctx, xfade_slice, &td, NULL, |
2239: ff_filter_execute(ctx, xfade_slice, &td, NULL, |
|
2219: FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); |
2240: FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); |
| 2220: |
2241: |