]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_xfade.c
avfilter: Constify all AVFilters
[ffmpeg] / libavfilter / vf_xfade.c
index adfcd759a81cb90d9ead1595537f81565c6e26ef..2e075cfb9aa4996c1661b2b7f11dbf5c81350e5a 100644 (file)
@@ -71,6 +71,8 @@ enum XFadeTransitions {
     WIPETR,
     WIPEBL,
     WIPEBR,
+    SQUEEZEH,
+    SQUEEZEV,
     NB_TRANSITIONS,
 };
 
@@ -195,6 +197,8 @@ static const AVOption xfade_options[] = {
     {   "wipetr",     "wipe tr transition",     0, AV_OPT_TYPE_CONST, {.i64=WIPETR},     0, 0, FLAGS, "transition" },
     {   "wipebl",     "wipe bl transition",     0, AV_OPT_TYPE_CONST, {.i64=WIPEBL},     0, 0, FLAGS, "transition" },
     {   "wipebr",     "wipe br transition",     0, AV_OPT_TYPE_CONST, {.i64=WIPEBR},     0, 0, FLAGS, "transition" },
+    {   "squeezeh",   "squeeze h transition",   0, AV_OPT_TYPE_CONST, {.i64=SQUEEZEH},   0, 0, FLAGS, "transition" },
+    {   "squeezev",   "squeeze v transition",   0, AV_OPT_TYPE_CONST, {.i64=SQUEEZEV},   0, 0, FLAGS, "transition" },
     { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=1000000}, 0, 60000000, FLAGS },
     { "offset",   "set cross fade start relative to first input stream", OFFSET(offset), AV_OPT_TYPE_DURATION, {.i64=0}, INT64_MIN, INT64_MAX, FLAGS },
     { "expr",   "set expression for custom transition", OFFSET(custom_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
@@ -1553,6 +1557,81 @@ static void wipebr##name##_transition(AVFilterContext *ctx,
 WIPEBR_TRANSITION(8, uint8_t, 1)
 WIPEBR_TRANSITION(16, uint16_t, 2)
 
+#define SQUEEZEH_TRANSITION(name, type, div)                                         \
+static void squeezeh##name##_transition(AVFilterContext *ctx,                        \
+                                const AVFrame *a, const AVFrame *b, AVFrame *out,    \
+                                float progress,                                      \
+                                int slice_start, int slice_end, int jobnr)           \
+{                                                                                    \
+    XFadeContext *s = ctx->priv;                                                     \
+    const float h = out->height;                                                     \
+    const int height = slice_end - slice_start;                                      \
+                                                                                     \
+    for (int p = 0; p < s->nb_planes; p++) {                                         \
+        const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
+        type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
+                                                                                     \
+        for (int y = 0; y < height; y++) {                                           \
+            const float z = .5f + ((slice_start + y) / h - .5f) / progress;          \
+                                                                                     \
+            if (z < 0.f || z > 1.f) {                                                \
+                for (int x = 0; x < out->width; x++)                                 \
+                    dst[x] = xf1[x];                                                 \
+            } else {                                                                 \
+                const int yy = lrintf(z * (h - 1.f));                                \
+                const type *xf0 = (const type *)(a->data[p] + yy * a->linesize[p]);  \
+                                                                                     \
+                for (int x = 0; x < out->width; x++)                                 \
+                    dst[x] = xf0[x];                                                 \
+            }                                                                        \
+                                                                                     \
+            dst += out->linesize[p] / div;                                           \
+            xf1 += b->linesize[p] / div;                                             \
+        }                                                                            \
+    }                                                                                \
+}
+
+SQUEEZEH_TRANSITION(8, uint8_t, 1)
+SQUEEZEH_TRANSITION(16, uint16_t, 2)
+
+#define SQUEEZEV_TRANSITION(name, type, div)                                         \
+static void squeezev##name##_transition(AVFilterContext *ctx,                        \
+                                const AVFrame *a, const AVFrame *b, AVFrame *out,    \
+                                float progress,                                      \
+                                int slice_start, int slice_end, int jobnr)           \
+{                                                                                    \
+    XFadeContext *s = ctx->priv;                                                     \
+    const float w = out->width;                                                      \
+    const int height = slice_end - slice_start;                                      \
+                                                                                     \
+    for (int p = 0; p < s->nb_planes; p++) {                                         \
+        const type *xf0 = (const type *)(a->data[p] + slice_start * a->linesize[p]); \
+        const type *xf1 = (const type *)(b->data[p] + slice_start * b->linesize[p]); \
+        type *dst = (type *)(out->data[p] + slice_start * out->linesize[p]);         \
+                                                                                     \
+        for (int y = 0; y < height; y++) {                                           \
+            for (int x = 0; x < out->width; x++) {                                   \
+                const float z = .5f + (x / w - .5f) / progress;                      \
+                                                                                     \
+                if (z < 0.f || z > 1.f) {                                            \
+                    dst[x] = xf1[x];                                                 \
+                } else {                                                             \
+                    const int xx = lrintf(z * (w - 1.f));                            \
+                                                                                     \
+                    dst[x] = xf0[xx];                                                \
+                }                                                                    \
+            }                                                                        \
+                                                                                     \
+            dst += out->linesize[p] / div;                                           \
+            xf0 += a->linesize[p] / div;                                             \
+            xf1 += b->linesize[p] / div;                                             \
+        }                                                                            \
+    }                                                                                \
+}
+
+SQUEEZEV_TRANSITION(8, uint8_t, 1)
+SQUEEZEV_TRANSITION(16, uint16_t, 2)
+
 static inline double getpix(void *priv, double x, double y, int plane, int nb)
 {
     XFadeContext *s = priv;
@@ -1700,6 +1779,8 @@ static int config_output(AVFilterLink *outlink)
     case WIPETR:     s->transitionf = s->depth <= 8 ? wipetr8_transition     : wipetr16_transition;     break;
     case WIPEBL:     s->transitionf = s->depth <= 8 ? wipebl8_transition     : wipebl16_transition;     break;
     case WIPEBR:     s->transitionf = s->depth <= 8 ? wipebr8_transition     : wipebr16_transition;     break;
+    case SQUEEZEH:   s->transitionf = s->depth <= 8 ? squeezeh8_transition   : squeezeh16_transition;   break;
+    case SQUEEZEV:   s->transitionf = s->depth <= 8 ? squeezev8_transition   : squeezev16_transition;   break;
     }
 
     if (s->transition == CUSTOM) {
@@ -1749,6 +1830,7 @@ static int xfade_frame(AVFilterContext *ctx, AVFrame *a, AVFrame *b)
     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out)
         return AVERROR(ENOMEM);
+    av_frame_copy_props(out, a);
 
     td.xf[0] = a, td.xf[1] = b, td.out = out, td.progress = progress;
     ctx->internal->execute(ctx, xfade_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
@@ -1769,6 +1851,11 @@ static int xfade_activate(AVFilterContext *ctx)
     FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
 
     if (s->xfade_is_over) {
+        if (!s->eof[0]) {
+            ret = ff_inlink_consume_frame(ctx->inputs[0], &in);
+            if (ret > 0)
+                av_frame_free(&in);
+        }
         ret = ff_inlink_consume_frame(ctx->inputs[1], &in);
         if (ret < 0) {
             return ret;
@@ -1779,10 +1866,9 @@ static int xfade_activate(AVFilterContext *ctx)
             ff_outlink_set_status(outlink, status, s->pts);
             return 0;
         } else if (!ret) {
-            if (ff_outlink_frame_wanted(outlink)) {
+            if (ff_outlink_frame_wanted(outlink))
                 ff_inlink_request_frame(ctx->inputs[1]);
-                return 0;
-            }
+            return 0;
         }
     }
 
@@ -1832,14 +1918,17 @@ static int xfade_activate(AVFilterContext *ctx)
         if (!s->eof[1] && ff_outlink_get_status(ctx->inputs[1])) {
             s->eof[1] = 1;
         }
-        if (!s->eof[0] && !s->xf[0])
+        if (!s->eof[0] && !s->xf[0] && ff_inlink_queued_frames(ctx->inputs[0]) == 0)
             ff_inlink_request_frame(ctx->inputs[0]);
-        if (!s->eof[1] && (s->need_second || s->eof[0]))
+        if (!s->eof[1] && (s->need_second || s->eof[0]) && ff_inlink_queued_frames(ctx->inputs[1]) == 0)
             ff_inlink_request_frame(ctx->inputs[1]);
         if (s->eof[0] && s->eof[1] && (
-            ff_inlink_queued_frames(ctx->inputs[0]) <= 0 ||
-            ff_inlink_queued_frames(ctx->inputs[1]) <= 0))
+            ff_inlink_queued_frames(ctx->inputs[0]) <= 0 &&
+            ff_inlink_queued_frames(ctx->inputs[1]) <= 0)) {
             ff_outlink_set_status(outlink, AVERROR_EOF, AV_NOPTS_VALUE);
+        } else if (s->xfade_is_over) {
+            ff_filter_set_ready(ctx, 100);
+        }
         return 0;
     }
 
@@ -1867,7 +1956,7 @@ static const AVFilterPad xfade_outputs[] = {
     { NULL }
 };
 
-AVFilter ff_vf_xfade = {
+const AVFilter ff_vf_xfade = {
     .name          = "xfade",
     .description   = NULL_IF_CONFIG_SMALL("Cross fade one video with another video."),
     .priv_size     = sizeof(XFadeContext),