使用 FFmpeg 进行视频淡入淡出的有效方法是什么?

Mar*_*tos 15 ffmpeg video-editing

在 FFmpeg 中,在两段视频内容之间进行交叉淡入淡出实际上是相当复杂的。没有像音频那样的“交叉淡入淡出”过滤器。

什么是有效的方法?

Mar*_*tos 22

TL;DR 版本:

此示例仅执行视频,假设两个视频剪辑具有相同的分辨率、帧速率等。这将在淡出剪辑和淡入淡出之间创建 1 秒淡入。假设fadeoutclip 是10 秒长。请注意,这是为了清楚起见而格式化的:它实际上是一行代码。

ffmpeg -i fadeoutclip.mp4 -i fadeinclip.mp4 -an \
-filter_complex "\
    [0:v]trim=start=0:end=9,setpts=PTS-STARTPTS[firstclip]; \
    [1:v]trim=start=1,setpts=PTS-STARTPTS[secondclip]; \
    [0:v]trim=start=9:end=10,setpts=PTS-STARTPTS[fadeoutsrc]; \
    [1:v]trim=start=0:end=1,setpts=PTS-STARTPTS[fadeinsrc]; \
    [fadeinsrc]format=pix_fmts=yuva420p, \
                fade=t=in:st=0:d=1:alpha=1[fadein]; \
    [fadeoutsrc]format=pix_fmts=yuva420p, \
                fade=t=out:st=0:d=1:alpha=1[fadeout]; \
    [fadein]fifo[fadeinfifo]; \
    [fadeout]fifo[fadeoutfifo]; \
    [fadeoutfifo][fadeinfifo]overlay[crossfade]; \
    [firstclip][crossfade][secondclip]concat=n=3[output] \
    " \
-map "[output]" <add in encoding part here>
Run Code Online (Sandbox Code Playgroud)

完整版本:

这是对这一切的解释:

输入规范...显而易见

ffmpeg -i fadeoutclip.mp4 -i fadeinclip.mp4 -an
Run Code Online (Sandbox Code Playgroud)

创建一个filter_complex: 假设您已经了解过滤器复合体:

-filter_complex
Run Code Online (Sandbox Code Playgroud)

首先,我们使用修剪过滤器将两个流分成两部分:内容和淡入淡出部分。淡出分为内容和淡出部分,而淡入分为淡出部分和内容。共四节。

请注意,严格来说,我们不具备打破淡入淡出部分指出:我们可以只指定淡出淡入时间的两个视频剪辑。但是,通过这样做,我们:

这四个部分中的每一个都指定了:开始时间(秒)、结束时间(秒)和神秘的setpts=PTS-STARTPTSfilter,它本质上使每个视频子剪辑从 0 秒开始。这在重新合成它们时至关重要。

请注意,说明s=0符是多余的,而这些说明符的setpts过滤器s=0也是多余的。但是,两者都是冗余指定的,以允许从 0 开始更改开始时间,而不会破坏过滤器复合体。此外,第二个内容剪辑运行到最后,因此e=未指定部分 (end=)。

    [0:v]trim=s=0:e=9,setpts=PTS-STARTPTS[firstclip];
    [1:v]trim=s=1,setpts=PTS-STARTPTS[secondclip];
    [0:v]trim=s=9:e=10,setpts=PTS-STARTPTS[fadeoutsrc];
    [1:v]trim=s=0:e=1,setpts=PTS-STARTPTS[fadeinsrc];
Run Code Online (Sandbox Code Playgroud)

接下来,我们指定淡入和淡出:我们首先通过指定像素格式yuva420p. 您实际上可以使用任何提供 Alpha 通道的格式。

接下来在这个过滤器子复合体中,我们指定一个淡出,一个淡入。alpha=1意味着视频本身不会变暗,只有透明度会“淡化”。st意味着开始,d意味着持续时间。

    [fadeinsrc]format=pix_fmts=yuva420p,      
                fade=t=in:st=0:d=1:alpha=1[fadein];
    [fadeoutsrc]format=pix_fmts=yuva420p,
                fade=t=out:st=0:d=1:alpha=1[fadeout];
Run Code Online (Sandbox Code Playgroud)

这是什么? fifo过滤器确保过滤器复合体中有可用的缓冲区空间。令人惊讶的是,这不是默认设置。如果不这样做,如果上面阶段的输出超过下面的叠加过滤器,则交叉淡入淡出可能会失败。是的,我知道你现在在想什么。这确实是一个 FFMPEG 错误

    [fadein]fifo[fadeinfifo];
    [fadeout]fifo[fadeoutfifo];
Run Code Online (Sandbox Code Playgroud)

现在,覆盖两个淡入淡出部分:通过确保两个交叉淡入淡出部分的大小相同,我们不必担心覆盖过滤器采用的相当讨厌的选项(因此我们在这里忽略它们):

    [fadeoutfifo][fadeinfifo]overlay[crossfade];
Run Code Online (Sandbox Code Playgroud)

最后,我们使用 concat filter将我们的三个段排列起来。

    [firstclip][crossfade][secondclip]concat=n=3[output]
Run Code Online (Sandbox Code Playgroud)

现在,将输出板映射为您的视频源。

不要忘记将像素格式设置为您通常使用的格式(通常为yuv420p),因为交叉淡入淡出部分会将其设置yuv420为输出通道!(因为我们没有指定它,你可以使用覆盖参数)当然,如果你想要yuv420,那么你很好:-)

-map "[output]" <add your normal encoding part here>
Run Code Online (Sandbox Code Playgroud)

然后您可以稍后重新组合音频(超出本问答的范围)


slh*_*hck 5

FFmpeg 现在有一个xfade(交叉淡入淡出)过滤器

您可以通过复杂的过滤器链在两个输入上使用它:

ffmpeg -i input1.mp4 -i input2.mp4 \
  -filter_complex "[0:v][1:v]xfade=transition=fade:duration=1:offset=2.5" \
  output.mp4
Run Code Online (Sandbox Code Playgroud)

此处,视频将被连接起来,2.5 秒后 ( offset=2.5) 第一个视频将淡入第二个视频,淡入淡出持续时间为一秒 ( duration=1)。

您可以在FFmpeg wiki上查看可用交叉渐变的示例。