注:本文包含部分作者脑补、臆测之内容,请不要全信。如遇与事实不符,望指正。如要了解 Melt 全部内容,请移步官网网站。

书接上回,装好了 qmelt、webvfx 之后就开始使用了,然后又是艰苦卓绝的一两天。

作为一个用惯了 FCPX 的视频剪辑(半个)老手,突然间让我写代码来剪视频,我是懵逼的。不过作为资深头发快掉光了的程序员,扫了一遍 Melt 的文档,感觉也不是很复杂,但事实证明我太 naive 😶了。官方文档中省略的内容太多,而仅有的几个例子也非常简单,根本没有覆盖常见的剪辑任务。

下面以我搞了一整天的视频作为例子讲解下 Melt 命令行工具的用法。

首先,要从视频文件中截取一段视频,可以这么写:

qmelt input.mp4 in=:0.5 out=:5.2 -consumer avformat:output.mp4

其中,input.mp4 作为视频输入源,in、out 指定截取范围,consumer 指定输出方式。工作流这是这样的:

+--------+   +--------+
|Producer|-->|Consumer|
+--------+   +--------+

上述把 mp4 文件作为输入源的 Producer 是 avformat ;还是其他的 Producer 类型,可以输入其他种类的视频来源。同样的,consumer 也有不同类型,这里使用的也是 avformat ——即把处理好的视频保存为视频文件。Producer、Consumer 可以指定参数,具体参数见官方文档(虽然文档里除了参数名和类型就没啥有用的信息了)。

另外要说的一点是 in、out 参数值的表示形式。官方文档里大部分地方写的是都整数形式的,表示的是帧数,比如 in=100 就表示从第 100 帧开始截取,但这非常不方便,要从时间换算,还得考虑视频文件本身的 fps。后来又增加了时间表示的形式,但文档里居然没提☹️,只有 一篇博客 提及了这种写法。所以在此类指定帧数的参数上用 00:00:00.00 的形式(及简写形式)来表示时间也是可以的。

当需要引入多个视频片段的时候,可以这样写:

qmelt \
    A.mov in=:1.0 out=:2.0 \
    timewarp:0.25:B.mov in=:2.0 out=:6.0 \
    C.mov in=:10.0 out=:12.0 \

这样就得到了3个串行视频组合的视频。

+---++---------++-----+
| A ||    B    ||  C  |
+---++---------++-----+

这里 timewarp 是另一种 Producer,用它可以调整输入视频的播放速度。顺便说下诡异之处,当在命令行里调用这个 Producer 时,in 参数的时间是正常播放时间,out 参数是调整播放速度后的时间,而在 mlt 文件里,两个参数都是调整后的时间🙄。

如果要在视频之间增加转场效果,就需要增加多轨,方法就是使用 -track 参数。

qmelt \
    A.mov in=:1.0 out=:2.0 \
    timewarp:0.25:B.mov in=:2.0 out=:6.0 \
    C.mov in=:10.0 out=:12.0 \
    -track D.mov out=:3.0

这样就生成了两轨视频:

+---++---------++-----+
| A ||    B    ||  C  |
+---++---------++-----+
+-------+
|   D   |
+-------+

添加到新轨上的视频会被移到最左边。需要注意的是,与常见的非线编辑软件的时间轴不同,上图中后添加的“轨”层级较高,即 D 会出现在 A 上面。 如果希望 D 在 C 后面播放,则需要在它之前增加空白帧:

qmelt \
    A.mov in=:1.0 out=:2.0 \
    timewarp:0.25:B.mov in=:2.0 out=:6.0 \
    C.mov in=:10.0 out=:12.0 \
    -track \
        -blank :7.0 \
        D.mov out=:3.0

这样即可满足:

+---++---------++-----+
| A ||    B    ||  C  |
+---++---------++-----+
                      +-------+
                      |   D   |
                      +-------+

然后增加转场:

qmelt \
    A.mov in=:1.0 out=:2.0 \
    timewarp:0.25:B.mov in=:2.0 out=:6.0 \
    C.mov in=:10.0 out=:12.0 \
    -track \
        -blank :7.0 \
        D.mov out=:3.0
    -transition luma in=:7.0 out=:9.0 a_track=0 b_track=1

咦,怎么没有效果?原来产生转场效果需要两轨上的视频要有点重合。

+---++---------++-----+
| A ||    B    ||  C  |
+---++---------++-----+
                   +-------+
                   |   D   |
                   +-------+

同时调整下时间

qmelt \
    A.mov in=:1.0 out=:2.0 \
    timewarp:0.25:B.mov in=:2.0 out=:6.0 \
    C.mov in=:10.0 out=:12.0 \
    -track \
        -blank :7.0 \
        D.mov out=:3.0
    -transition luma in=:5.0 out=:7.0 a_track=0 b_track=1

这样就完成了一个第 5 秒到第 7 秒从第 0 轨到第 1 轨切换的转场效果。

如果使用 webvfx 的话,webvfx 官方 demo 中有个 transition-shader-glslio,对应了很多酷炫的 GL 的效果,不妨试试。

Melt 还有 filter 的机制,位于 Producer 和 Consumer 之间,为中间状态的视频添加效果。

+--------+   +------+   +--------+
|Producer|-->|Filter|-->|Consumer|
+--------+   +------+   +--------+

可以用元素的或者webvfx的:

-filter webvfx \
    resource=effects/filter-banner.html in=:0.0 out=:2.0 \
    FadeIn=.4 FadeOut=.2 Title="哈哈哈"
-filter avfilter.lut3d \
    av.file="effects/Free LUT/deluts_armchair.cube" 

这里需要注意的是,除了 -filter 还是其他几个 -attach 参数指定不同的作用范围,具体咋样的我也没闹清楚。

除了 -track,还是有 -video-track-audio-track,可以特别指定这条是视频轨还是音频轨。比如我要增加一个 bgm,又不想要 bgm 这轨把前面的画面挡住,那么指定 --audio-track 就可以避免

-audio-track bgm.mp3 out=:42.0

如果想要实现音频渐入渐出的效果,搜出来一堆让用 transition 做的,我试下来没啥软用,就是有用,那也麻烦得很。其实 Melt 也有 关键帧属性动画 的功能

keyframeable-effects

可以这样写:

-audio-track bgm.mp3 out=:42.0 \
    -attach volume level="0=5dB; :6.0=-10dB; :40.0=-10dB; :44.0=-50dB"

这边我也卡了很久,文档里写的时间前写负号-就表示相对视频结尾的时间,但我试下来他妈的不管用。用 ~ 来表示“smooth spline keyframes”的功能我也闹不清楚是从之前那一个关键帧还是从它本身开始平滑插值。扒源码看,mlt_animation.c 里注释解释了下,所以是从该帧开始的。

If an exclamation point (!) or vertical bar (|) character preceeds the equal sign, then the keyframe interpolation is set to discrete. If a tilde (~) preceeds the equal sign, then the keyframe interpolation is set to smooth (spline).

还是一个特别诡异的地方,同样是使用 -consumer avformat:output.mp4,如果指定了 width, height 那么导出的视频是 25fps 的;如果没有指定就是跟输入视频的 fps 是一样的,但如果用 timewarp Producer 那么这段视频的时间就算不清楚了。

还有问题,Melt 命令行做不到直接用 -filter 给整个视频增加水印,那想着挨个给 -track 加 -filter watermark 吧,结果有两个就会报 Segmentation Fault 的错,晕。又想着那我导出 mlt 文件,人肉改 mlt 可以给 Tractor 再套一个 Tractor 就可以加了,结果发现用导出 mlt 再跑出来的视频莫名地结尾多了很对的空白帧,貌似就是因为存在 timewarp Producer 导致的时间算不准的问题。最后只得跑两次命令,先产出没水印的视频,再加水印。

折腾了一整天,搞出这么一个:

qmelt \
    -track \
        apple-animation.mov in=:0.5 out=:5.2 \
        timewarp:0.25:apple-animation.mov in=:2.0 out=:6.0 \
        timewarp:0.25:apple-animation.mov in=:4.5 out=:7.0 \
        apple-animation.mov in=:10.0 out=:16.0 \
        timewarp:0.25:apple-animation.mov in=:16.4 out=:22.0 \
        timewarp:0.25:apple-animation.mov in=:18.0 out=:24.0 \
        apple-animation.mov in=:19.5 out=:22.0 \
        -filter webvfx \
            resource=effects/filter-banner.html in=:0.0 out=:2.0 \
            FadeIn=.4 FadeOut=.2 Title="It's what we say<br>\"Design\"" \
    -track \
        -blank :28.0 \
        apple-animation.mov in=:33.0 out=:47.0 \
    -transition webvfx \
        resource=effects/transition-shader-glslio.html in=:28.0 out=:30.0 \
        glslio_name=crosshatch \
    -audio-track bgm.mp3 out=:42.0 \
        -attach volume level="0=5dB; :6.0=-10dB; :40.0=-10dB; :44.0=-50dB" \
    -consumer avformat target=output/`date +%s`.mp4 width=360 height=640

最终效果是这样的:

搞这个东西最蛋疼的就是改的时候根本不知道效果会怎么样。是不是我写错了?是不是参数不对?是不是插件没用对?是不是程序有 bug?都不知道!每次改了都要生成一次,鬼知道我经历了什么。

trash

完。


通过 brew 安装的 melt 只带了一部分的插件,所以要使用某个插件(producer, consumer, filter, transition)的时候,正确的打开方式是先用 qmelt -query XXXXX 查一下有没有这个插件,如果没有的话就需要安装。否则直接使用的话,melt 不会报错,但就是没有效果,多次尝试未果后容易导致情绪崩溃(多么痛的领悟!)。

qmelt -query producers | grep qimage
>  - qimage

那么怎么安装插件呢?首先从 gayhub 下载源码,要从 release 列表里下载对应当前 melt 版本的代码,否则编译出来的库可能会 failed to dlopen(多么痛的领悟again)。进入 src/modules 目录,这里有各种插件的源码。比如要安装 movit.* 系列插件,对应的文件夹是 opengl,进入后执行 ./configure 提示缺少依赖 movit 库,所以再安装 movit 库,然后:

./configure
make
make install

即可成功安装。