[PATCH] fade: extend start and duration syntax

Stefano Sabatini stefano.sabatini-lala
Mon Feb 21 18:03:13 CET 2011


Make the fade filter support start time and effect duration as a
number of seconds, rather than by using a number of frames.
---
 doc/filters.texi      |   41 ++++++++++----
 libavfilter/vf_fade.c |  153 ++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 149 insertions(+), 45 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index bbc730d..da61424 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -469,33 +469,52 @@ For more information about libfreetype, check:
 
 Apply fade-in/out effect to input video.
 
+At the end of the fade-in effect the output video will have the same
+intensity as the input video, at the end of the fade-out transition
+the output video will be completely black.
+
 It accepts the parameters:
- at var{type}:@var{start_frame}:@var{nb_frames}
+ at var{type}:@var{start}:@var{duration}
 
 @var{type} specifies if the effect type, can be either "in" for
 fade-in, or "out" for a fade-out effect.
 
- at var{start_frame} specifies the number of the start frame for starting
-to apply the fade effect.
+ at var{start} specifies the beginning of the fade transition.  If the
+string is of the form "#@var{N}", @var{N} specifies the start frame
+number, otherwise the string is interpreted as as start time,
+expressed in seconds or as time string of the form
+ at var{HH}:@var{MM}:@var{SS}[. at var{MICROSECONDS}].
 
- at var{nb_frames} specifies the number of frames for which the fade
-effect has to last. At the end of the fade-in effect the output video
-will have the same intensity as the input video, at the end of the
-fade-out transition the output video will be completely black.
+ at var{duration} specifies the duration of the fade effect.  If the
+string is of the form "#@var{N}", @var{N} specifies the number of
+frames for which the fade effect has to last, otherwise the string is
+interpreted as a duration, expressed in seconds or as a time string of
+the form @var{HH}:@var{MM}:@var{SS}[. at var{MICROSECONDS}].
 
 A few usage examples follow, usable too as test scenarios.
 @example
 # fade in first 30 frames of video
-fade=in:0:30
+fade=in:#0:#30
+
+# fade in first 5 seconds of video
+fade=in:0:5
 
 # fade out last 45 frames of a 200-frame video
-fade=out:155:45
+fade=out:#155:#45
+
+# fade out last 10 seconds frames of a 5 minutes video
+# the quotes are required, since the time specification includes ":"
+fade=out:'00:04:50':10
 
 # fade in first 25 frames and fade out last 25 frames of a 1000-frame video
-fade=in:0:25, fade=out:975:25
+fade=in:#0:#25, fade=out:#975:#25
 
 # make first 5 frames black, then fade in from frame 5-24
-fade=in:5:20
+fade=in:#5:#20
+
+# make first two seconds black, then fade in the following 5 seconds
+fade=in:2:5
+
 @end example
 
 @section fifo
diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c
index 203a186..d2712fd 100644
--- a/libavfilter/vf_fade.c
+++ b/libavfilter/vf_fade.c
@@ -25,45 +25,107 @@
  * based heavily on vf_negate.c by Bobby Bingham
  */
 
+#define DEBUG
+
+#include "libavutil/avstring.h"
+#include "libavutil/parseutils.h"
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
 
 typedef struct {
-    int factor, fade_per_frame;
-    unsigned int frame_index, start_frame, stop_frame;
+    int factor;
+    enum { FADE_IN, FADE_OUT } type;
+    int frame_index, start_frame, nb_frames;
     int hsub, vsub, bpp;
+    uint64_t start_time;
+    uint64_t duration_time;
 } FadeContext;
 
 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 {
     FadeContext *fade = ctx->priv;
-    unsigned int nb_frames;
-    char in_out[4];
+    int ret;
+    char *in_out, *start, *duration, *tail;
+    unsigned long int ul;
+
+    fade->start_frame = -1;
+    fade->nb_frames   = -1;
 
-    if (!args ||
-        sscanf(args, " %3[^:]:%u:%u", in_out, &fade->start_frame, &nb_frames) != 3) {
+    if (!args) {
         av_log(ctx, AV_LOG_ERROR,
-               "Expected 3 arguments '(in|out):#:#':'%s'\n", args);
+               "Expected 3 arguments '(in|out):#:#':'%s'\n", args ? args : "");
         return AVERROR(EINVAL);
     }
 
-    nb_frames = nb_frames ? nb_frames : 1;
-    fade->fade_per_frame = (1 << 16) / nb_frames;
-    if (!strcmp(in_out, "in"))
-        fade->factor = 0;
-    else if (!strcmp(in_out, "out")) {
-        fade->fade_per_frame = -fade->fade_per_frame;
-        fade->factor = (1 << 16);
+    in_out = av_get_token(&args, ":");
+    if (!strcmp(in_out, "in")) {
+        fade->type = FADE_IN;
+    } else if (!strcmp(in_out, "out")) {
+        fade->type = FADE_OUT;
     } else {
         av_log(ctx, AV_LOG_ERROR,
-               "first argument must be 'in' or 'out':'%s'\n", in_out);
+               "First argument must be 'in' or 'out':'%s'\n", in_out);
+        return AVERROR(EINVAL);
+    }
+    av_freep(&in_out);
+
+    if (args) args++;
+    start = av_get_token(&args, ":");
+    if (!start) {
+        av_log(ctx, AV_LOG_ERROR, "start was not specified\n");
+        return AVERROR(EINVAL);
+    }
+    if (*start == '#') {
+        ul = strtoul(start+1, &tail, 10);
+        if (ul > INT_MAX || *tail) {
+            av_log(ctx, AV_LOG_ERROR,
+                   "Invalid or too big frame value number for start frame: '%s'\n", start);
+            return AVERROR(EINVAL);
+        }
+        fade->start_frame = ul;
+    } else {
+        if ((ret = av_parse_time(&fade->start_time, start, 1)) < 0) {
+            av_log(ctx, AV_LOG_ERROR,
+                   "Invalid or too big start frame time specification: '%s'\n", start);
+            return ret;
+        }
+    }
+    av_freep(&start);
+
+    if (args) args++;
+    duration = av_get_token(&args, ":");
+    if (!duration) {
+        av_log(ctx, AV_LOG_ERROR, "duration was not specified\n");
         return AVERROR(EINVAL);
     }
-    fade->stop_frame = fade->start_frame + nb_frames;
+    if (*duration == '#') {
+        ul = strtoul(duration+1, &tail, 10);
+        if (ul > INT_MAX || *tail) {
+            av_log(ctx, AV_LOG_ERROR,
+                   "Invalid frame value number for duration: '%s'\n", duration);
+            return AVERROR(EINVAL);
+        }
+        fade->nb_frames = ul;
+        fade->nb_frames = fade->nb_frames ? fade->nb_frames : 1;
+    } else {
+        if ((ret = av_parse_time(&fade->duration_time, duration, 1)) < 0) {
+            av_log(ctx, AV_LOG_ERROR,
+                   "Invalid duration time specification: '%s'\n", duration);
+            return AVERROR(EINVAL);
+        }
+    }
+    av_freep(&duration);
+
+    av_log(ctx, AV_LOG_INFO, "type:%s", fade->type == FADE_IN ? "in" : "out");
+    if (fade->start_frame >= 0)
+        av_log(ctx, AV_LOG_INFO, " start_frame:%d", fade->start_frame);
+    else
+        av_log(ctx, AV_LOG_INFO, " start_time:%f", (double)fade->start_time / AV_TIME_BASE);
+    if (fade->nb_frames >= 0)
+        av_log(ctx, AV_LOG_INFO, " nb_frames:%d\n", fade->nb_frames);
+    else
+        av_log(ctx, AV_LOG_INFO, " duration:%f\n", (double)fade->duration_time / AV_TIME_BASE);
 
-    av_log(ctx, AV_LOG_INFO,
-           "type:%s start_frame:%d nb_frames:%d\n",
-           in_out, fade->start_frame, nb_frames);
     return 0;
 }
 
@@ -94,6 +156,42 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+{
+    AVFilterContext *ctx = inlink->dst;
+    FadeContext *fade = ctx->priv;
+    double factor = 0;
+    uint64_t current_time = av_rescale_q(picref->pts, ctx->inputs[0]->time_base,
+                                         AV_TIME_BASE_Q);
+
+    if (fade->start_frame < 0 && current_time >= fade->start_time)
+        fade->start_frame = fade->frame_index;
+
+    /* compute fade factor */
+    if (fade->start_frame >= 0 && fade->frame_index >= fade->start_frame) {
+        /* fade duration is specified as a number of frames */
+        if (fade->nb_frames >= 0 &&
+            fade->frame_index - fade->start_frame <= fade->nb_frames) {
+            factor = (double)(fade->frame_index - fade->start_frame) / fade->nb_frames;
+        /* fade duration is specified as an number of microseconds */
+        } else if (current_time <= fade->start_time + fade->duration_time) {
+            factor = (double)(current_time - fade->start_time) / fade->duration_time;
+        } else
+            factor = 1.0;
+    }
+
+    if (fade->type == FADE_OUT)
+        factor = 1 - factor;
+    fade->factor = av_clip_uint16(factor * ((1<<16)-1));
+
+    av_dlog(ctx, "frame:%d time:%f factor:%d rel_factor:%f\n",
+            fade->frame_index, (double)current_time / AV_TIME_BASE,
+            fade->factor, factor);
+    fade->frame_index++;
+
+    avfilter_start_frame(inlink->dst->outputs[0], picref);
+}
+
 static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
 {
     FadeContext *fade = inlink->dst->priv;
@@ -134,19 +232,6 @@ static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
     avfilter_draw_slice(inlink->dst->outputs[0], y, h, slice_dir);
 }
 
-static void end_frame(AVFilterLink *inlink)
-{
-    FadeContext *fade = inlink->dst->priv;
-
-    avfilter_end_frame(inlink->dst->outputs[0]);
-
-    if (fade->frame_index >= fade->start_frame &&
-        fade->frame_index <= fade->stop_frame)
-        fade->factor += fade->fade_per_frame;
-    fade->factor = av_clip_uint16(fade->factor);
-    fade->frame_index++;
-}
-
 AVFilter avfilter_vf_fade = {
     .name          = "fade",
     .description   = NULL_IF_CONFIG_SMALL("Fade in/out input video"),
@@ -158,9 +243,9 @@ AVFilter avfilter_vf_fade = {
                                     .type            = AVMEDIA_TYPE_VIDEO,
                                     .config_props    = config_props,
                                     .get_video_buffer = avfilter_null_get_video_buffer,
-                                    .start_frame      = avfilter_null_start_frame,
+                                    .start_frame     = start_frame,
                                     .draw_slice      = draw_slice,
-                                    .end_frame       = end_frame,
+                                    .end_frame       = avfilter_null_end_frame,
                                     .min_perms       = AV_PERM_READ | AV_PERM_WRITE,
                                     .rej_perms       = AV_PERM_PRESERVE, },
                                   { .name = NULL}},
-- 
1.7.2.3


--ZPt4rx8FFjLCG7dd--



More information about the ffmpeg-devel mailing list