mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-11 17:55:21 +00:00
lavfi/fade: Added ability to do video fade based on timestamp
This commit is contained in:
parent
ebea370dc3
commit
4ac2da3793
@ -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
|
||||
|
@ -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->stop_frame = fade->start_frame + fade->nb_frames;
|
||||
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);
|
||||
}
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user