如何在ffmpeg中从一个视频淡入另一个视频,包括音频和视频

如何在ffmpeg中从一个视频淡入另一个视频,包括音频和视频

我一直在尝试使用ffmpeg 中的xfade(视频)和acrossfade(音频)过滤器来允许两个输入视频之间的“淡入淡出”,但我实际上并没有找到一种方法来让 ffmpeg 正确地淡入淡出视频的视频和音频,而不会导致音频不同步。 xfade有一个offset选项,所以如果我想让第一个视频在 5 秒后开始 2 秒的淡入淡出,我可以说:

ffmpeg -i first.mp4 -i second.mp4 -filter_complex "[0v][1v]xfade=transition=fade:duration=2:offset=5;[0:a][1:a]acrossfade=d=2:c1=tri:c2=tri" output.mp4

但是,正如您在上文中注意到的,acrossfade没有offset选项。我推测它所做的只是将一个视频的末尾的音频淡入淡出到另一个视频的开头,这将导致不同步,因为视频淡入淡出会在第一个视频中切入 5 秒。

有没有办法让音频和视频保持同步?我是否遗漏了acrossfade过滤器的某些功能,导致它没有参数offset,或者这只是一个xfade有但acrossfade没有的额外功能?

答案1

所以,这不是一个特别简单的操作;虽然可以做到,但用 ffmpeg 做起来很麻烦。我将从基本的计算数字的方法开始,然后将它们插入必要的命令中,最后我会解释。

计算:

  • $$offset= 淡入淡出过渡之前第一个视频播放多少秒(例如:10)
  • $$duration= 淡入淡出过渡的持续时间(例如:4)
  • $$trimlength= $$offset+$$duration

鉴于上述变量,以下从一个输入视频淡入淡出到另一个输入视频(视频和音频),对视频和音频使用标准淡入淡出过渡,持续 4 秒,过渡从第一个视频的 10 秒开始:

ffmpeg ^
  -i first.mp4 ^
  -i second.mp4 ^
  -filter_complex "[0v][1v]xfade=transition=fade:duration=$$duration:offset=$$offset[video];[0:a]atrim=0:$$trimlength[0A];[0A][1:a]acrossfade=d=$$duration:c1=tri:c2=tri[audio]" ^
  -map "[video]" -map "[audio]" ^
  output.mp4

这转换为以下命令并替换变量的值:

ffmpeg ^
  -i first.mp4 ^
  -i second.mp4 ^
  -filter_complex "[0v][1v]xfade=transition=fade:duration=4:offset=10[video];[0:a]atrim=0:14[0A];[0A][1:a]acrossfade=d=4:c1=tri:c2=tri[audio]" ^
  -map "[video]" -map "[audio]" ^
  output.mp4

^ 上述音频曲线“tri”是线性的,音频淡入淡出有时用指数曲线听起来会更好;请指定“exp”来使用它们。也可以尝试其他曲线类型,更不用说不同的视频淡入淡出过渡效果了!

注意:我发现这些淡入淡出所涉及的额外处理可能会导致 ffmpeg 输出比输入 MP4 更“高级”的 MP4(例如高 4:4:4 配置文件而不是主配置文件),而一些较旧或更基本的视频播放软件可能不支持(*咳咳* Telegram 的内置视频播放器 *咳咳*)。要使其输出主配置文件视频,请添加-profile:v main -pix_fmt yuv420p; 例如:

ffmpeg ^
  -i first.mp4 ^
  -i second.mp4 ^
  -filter_complex "[0v][1v]xfade=transition=fade:duration=4:offset=10[video];[0:a]atrim=0:14[0A];[0A][1:a]acrossfade=d=4:c1=tri:c2=tri[audio]" ^
  -map "[video]" -map "[audio]" ^
  -profile:v main -pix_fmt yuv420p ^
  output.mp4

解释:
ffmpeg 有点乱,但我不想说得太直白。不同的团队以不同的方式实现不同的过滤器,这导致不同的参数语法样式和不同的功能;有些过滤器的功能比其他过滤器更多,即使对于看起来功能相似、应该具有相同语法和功能的过滤器也是如此。

在此例中,xfade(视频)滤镜比(音频)滤镜更强大,acrossfade因为它可以接受偏移。您可以说“在第一个视频上运行 10 秒,然后过渡到第二个视频 4 秒,这样第一个视频的第 10-14 秒和第二个视频的第 0-4 秒就会以淡入淡出效果混合在一起。

但是,该acrossfade过滤器没有偏移功能。您只能说“运行整个第一个音频减去过渡长度,然后进行 4 秒过渡到第二个音频,这样第一个音频的($len-4)0-4秒$len和第二个音频的 0-4 秒就会以淡入淡出效果混合在一起。

因为您无法使用 crossfade 指定偏移选项,所以您必须模拟它。您可以通过首先将输入音频修剪为所需偏移量的长度加上过渡长度来实现此目的;如果您将其修剪为 14 秒并指定 4 秒的过渡长度,那么您将有效地获得 10 秒的偏移量和最后的 4 秒过渡,因为 crossfade 只占用音频流中可用的最后 4 秒。因此,要做到这一点,您首先将第一个音频流传递给过滤atrim器以执行此操作,将修剪后的流映射到句柄[0A],然后将其传递给过滤器acrossfade。您修剪为atrim偏移量+持续时间的长度,然后修剪为持续时间。将它们放在一起,在最后acrossfade映射[video]和流以产生输出。[audio]

当你计算第一个视频的偏移量和过渡时长时,获取第一个视频的准确长度会很有用,这样你就可以确保计算正确稍微短一点比第一个视频长度更长 - 如果您想在输出中包含整个第一个视频 - 以避免超出范围。您可以使用ffprobe以下方式获取此长度:

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 first.mp4

有关这两个过滤器的更多自定义信息,请参阅文档:
https://ffmpeg.org/ffmpeg-filters.html#xfade
https://ffmpeg.org/ffmpeg-filters.html#acrossfade

相关内容