[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