aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Martin <andyndeanna@gmail.com>2013-04-16 21:35:02 -0400
committerClément Bœsch <ubitux@gmail.com>2013-04-21 20:57:02 +0200
commit4ac2da37938354d305178da91d3e3718334de4a5 (patch)
tree34e2f1142bd69cb125705bc5fb2f5526b6e12e8f
parentebea370dc3909aa182bae4c728b83516a904beca (diff)
downloadffmpeg-4ac2da37938354d305178da91d3e3718334de4a5.tar.gz
lavfi/fade: Added ability to do video fade based on timestamp
-rw-r--r--doc/filters.texi18
-rw-r--r--libavfilter/vf_fade.c95
2 files changed, 97 insertions, 16 deletions
diff --git a/doc/filters.texi b/doc/filters.texi
index a4a0893186..1a93309871 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -3131,6 +3131,17 @@ Default is 25.
@item alpha
If set to 1, fade only alpha channel, if one exists on the input.
Default value is 0.
+
+@item start_time, st
+Specify the timestamp (in seconds) of the frame to start to apply the fade
+effect. If both start_frame and start_time are specified, the fade will start at
+whichever comes last. Default is 0.
+
+@item duration, d
+The number of seconds 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.
+If both duration and nb_frames are specified, duration is used. Default is 0.
@end table
@subsection Examples
@@ -3171,6 +3182,13 @@ Fade in alpha over first 25 frames of video:
@example
fade=in:0:25:alpha=1
@end example
+
+@item
+Make first 5.5 seconds black, then fade in for 0.5 seconds:
+@example
+fade=t=in:st=5.5:d=0.5
+@end example
+
@end itemize
@section field
diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c
index 71e0f01208..4dbd4c7d37 100644
--- a/libavfilter/vf_fade.c
+++ b/libavfilter/vf_fade.c
@@ -54,13 +54,14 @@ typedef struct {
int type;
int factor, fade_per_frame;
int start_frame, nb_frames;
- unsigned int frame_index, stop_frame;
+ unsigned int frame_index;
int hsub, vsub, bpp;
unsigned int black_level, black_level_scaled;
uint8_t is_packed_rgb;
uint8_t rgba_map[4];
int alpha;
-
+ uint64_t start_time, duration;
+ enum {VF_FADE_WAITING=0, VF_FADE_FADING, VF_FADE_DONE} fade_state;
} FadeContext;
static av_cold int init(AVFilterContext *ctx)
@@ -68,18 +69,27 @@ static av_cold int init(AVFilterContext *ctx)
FadeContext *fade = ctx->priv;
fade->fade_per_frame = (1 << 16) / fade->nb_frames;
- if (fade->type == FADE_IN) {
- fade->factor = 0;
- } else if (fade->type == FADE_OUT) {
- fade->fade_per_frame = -fade->fade_per_frame;
- fade->factor = (1 << 16);
+ fade->fade_state = VF_FADE_WAITING;
+
+ if (fade->duration != 0) {
+ // If duration (seconds) is non-zero, assume that we are not fading based on frames
+ fade->nb_frames = 0; // Mostly to clean up logging
+ }
+
+ // Choose what to log. If both time-based and frame-based options, both lines will be in the log
+ if (fade->start_frame || fade->nb_frames) {
+ av_log(ctx, AV_LOG_VERBOSE,
+ "type:%s start_frame:%d nb_frames:%d alpha:%d\n",
+ fade->type == FADE_IN ? "in" : "out", fade->start_frame,
+ fade->nb_frames,fade->alpha);
+ }
+ if (fade->start_time || fade->duration) {
+ av_log(ctx, AV_LOG_VERBOSE,
+ "type:%s start_time:%f duration:%f alpha:%d\n",
+ fade->type == FADE_IN ? "in" : "out", (fade->start_time / (double)AV_TIME_BASE),
+ (fade->duration / (double)AV_TIME_BASE),fade->alpha);
}
- fade->stop_frame = fade->start_frame + fade->nb_frames;
- av_log(ctx, AV_LOG_VERBOSE,
- "type:%s start_frame:%d nb_frames:%d alpha:%d\n",
- fade->type == FADE_IN ? "in" : "out", fade->start_frame,
- fade->nb_frames, fade->alpha);
return 0;
}
@@ -153,6 +163,55 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
FadeContext *fade = inlink->dst->priv;
uint8_t *p;
int i, j, plane;
+ double frame_timestamp = frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base);
+
+ // Calculate Fade assuming this is a Fade In
+ if (fade->fade_state == VF_FADE_WAITING) {
+ fade->factor=0;
+ if ((frame_timestamp >= (fade->start_time/(double)AV_TIME_BASE))
+ && (fade->frame_index >= fade->start_frame)) {
+ // Time to start fading
+ fade->fade_state = VF_FADE_FADING;
+
+ // Save start time in case we are starting based on frames and fading based on time
+ if ((fade->start_time == 0) && (fade->start_frame != 0)) {
+ fade->start_time = frame_timestamp*(double)AV_TIME_BASE;
+ }
+
+ // Save start frame in case we are starting based on time and fading based on frames
+ if ((fade->start_time != 0) && (fade->start_frame == 0)) {
+ fade->start_frame = fade->frame_index;
+ }
+ }
+ }
+ if (fade->fade_state == VF_FADE_FADING) {
+ if (fade->duration == 0) {
+ // Fading based on frame count
+ fade->factor = (fade->frame_index - fade->start_frame) * fade->fade_per_frame;
+ if (fade->frame_index > (fade->start_frame + fade->nb_frames)) {
+ fade->fade_state = VF_FADE_DONE;
+ }
+
+ } else {
+ // Fading based on duration
+ fade->factor = (frame_timestamp - (fade->start_time/(double)AV_TIME_BASE))
+ * (float) UINT16_MAX / (fade->duration/(double)AV_TIME_BASE);
+ if (frame_timestamp > ((fade->start_time/(double)AV_TIME_BASE)
+ + (fade->duration/(double)AV_TIME_BASE))) {
+ fade->fade_state = VF_FADE_DONE;
+ }
+ }
+ }
+ if (fade->fade_state == VF_FADE_DONE) {
+ fade->factor=UINT16_MAX;
+ }
+
+ fade->factor = av_clip_uint16(fade->factor);
+
+ // Invert fade_factor if Fading Out
+ if (fade->type == 1) {
+ fade->factor=UINT16_MAX-fade->factor;
+ }
if (fade->factor < UINT16_MAX) {
if (fade->alpha) {
@@ -188,10 +247,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
}
- 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++;
return ff_filter_frame(inlink->dst->outputs[0], frame);
@@ -215,6 +270,14 @@ static const AVOption fade_options[] = {
{ "n", "Number of frames to which the effect should be applied.",
OFFSET(nb_frames), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, INT_MAX, FLAGS },
{ "alpha", "fade alpha if it is available on the input", OFFSET(alpha), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FLAGS },
+ { "start_time", "Number of seconds of the beginning of the effect.",
+ OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "st", "Number of seconds of the beginning of the effect.",
+ OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "duration", "Duration of the effect in seconds.",
+ OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "d", "Duration of the effect in seconds.",
+ OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
{ NULL },
};