我有一个 Bash 脚本,它在给定的视频文件上运行 FFmpeg,并且 - 连同许多其他东西 - 使用叠加层为其添加了 PNG 水印。我希望能够通过用户输入启用或禁用它来仅在某些视频上应用水印,但我知道的唯一方法是有条件地分支两个单独的 FFmpeg 命令 - 一个添加水印,一个那不是。
以下是用于比较的两个命令。
带水印:
ffmpeg -y -i "$1" -i "outro.mp4" -loop 1 -i "../Watermark/watermark3.png" \
-movflags +faststart \
-preset ultrafast \
-filter_complex \
"color=black:16x16:d=$total[base]; \
[0:v]scale=-2:'max(1080,ih)',setpts=PTS-STARTPTS[v0]; \
[1:v]fade=in:st=0:d=$fadeduration:alpha=1,setpts=PTS-STARTPTS+(($fadetime)/TB)[v1]; \
[2:v]lut=a=val*0.7,fade=in:st=5:d=2:alpha=1,fade=out:st=$length1:d=2:alpha=1[v2]; \
[base][v0]scale2ref[base][v0]; \
[base][v0]overlay[tmp]; \
[tmp][v1]overlay,setsar=1[tmp2]; \
[v2][tmp2]scale2ref=w=oh*mdar:h=ih*0.1[wm_scaled][video]; \
[video][wm_scaled]overlay=W-w-50:50:format=auto:shortest=1[outv]; \
[0:a][1:a]acrossfade=d=$fadeduration[outa]" \
-map "[outv]" -map "[outa]" -c:v libx264 -c:a libopus -crf 17 "$output"
无水印:
ffmpeg -y -i "$1" -i "outro.mp4" -loop 1 -i "../Watermark/watermark3.png" \
-movflags +faststart \
-preset ultrafast \
-filter_complex \
"color=black:16x16:d=$total[base]; \
[0:v]scale=-2:'max(1080,ih)',setpts=PTS-STARTPTS[v0]; \
[1:v]fade=in:st=0:d=$fadeduration:alpha=1,setpts=PTS-STARTPTS+(($fadetime)/TB)[v1]; \
[base][v0]scale2ref[base][v0]; \
[base][v0]overlay[tmp]; \
[tmp][v1]overlay,setsar=1[tmp2]; \
[tmp2]setsar=1[outv]; \
[0:a][1:a]acrossfade=d=$fadeduration[outa]" \
-map "[outv]" -map "[outa]" -c:v libx264 -c:a libopus -crf 17 "$output"
这并不理想,因为它需要我维护两个 90% 相同的不同命令,这违反了 DRY 原则并导致两次维护。更不用说,每次我想以相同的方式有条件地启用另一个功能时,我还需要另外两个命令排列,所以它根本不是面向未来的,而且很容易很快变成意大利面条代码。
FFmpeg 中是否有任何东西可以让我根据用户输入有条件地启用/禁用某个过滤器?如果没有,完成这样的事情的最佳方法是什么?
在最初的测试中,我认为这会非常复杂,但结果比预期的要简单 - 它可以完全在 Bash 中处理,方法是将每个引用条件流的流包装在一个变量中。
真正的麻烦 - 正如pigeonburger猜测的那样 - 在于处理对流的所有引用,尤其是输出视频的最后一个:这个流的变量需要有条件地设置其内容,在我的情况下还涉及使用“虚拟" 过滤器喜欢
setsar=1
避免空流错误。之后,最困难的部分是确保所有流标签在两种条件下都匹配——如果不匹配,则需要像最终流一样有条件地重命名它们。
下面的示例询问用户是否要对视频应用水印:如果输入的不是
N
orn
,它会通过设置必要的流然后运行 FFmpeg 命令来应用水印。尽管它可能远不如我做的更好的 Bash 程序员那样健壮或简洁,但它绝对比混淆两个单独命令的替代方案更简洁和更易于维护。