使用ffmpeg如何垂直或水平堆叠(拼接)多个视频?

83

我有两个完全相同长度的视频,我想使用ffmpeg将它们叠加成一个视频文件。

我该如何做?

3个回答

280

使用 vstack(竖直堆叠)、hstack(水平堆叠)或xstack(自定义布局)滤镜。相比其他方法,它更加简单快捷。

合并/堆叠两个视频或图像

竖直堆叠

使用 vstack 滤镜。

enter image description here

ffmpeg -i input0 -i input1 -filter_complex vstack=inputs=2 output

视频必须具有相同的宽度。

水平

使用hstack过滤器。

enter image description here

ffmpeg -i input0 -i input1 -filter_complex hstack=inputs=2 output

视频必须具有相同的高度。

带边框

使用pad滤镜。此示例在两侧之间创建了一个 5px 黑色边框。

enter image description here

ffmpeg -i input0 -i input1 -filter_complex "[0]pad=iw+5:color=black[left];[left][1]hstack=inputs=2" output

使用音频

混合并使用原始通道位置

在此输入图片描述

添加 amerge 滤镜来合并两个输入的音频通道:

ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];[0:a][1:a]amerge=inputs=2[a]" -map "[v]" -map "[a]" -ac 2 output
  • 假设每个输入都包含立体声音频流。

  • 如果两个输入都包含多声道音频,则包括 -ac 2 以混合为立体声。例如,如果两个输入都是立体声,则在省略 -ac 2 的情况下会得到一个4通道输出音频流而不是立体声。

将每个输入的所有音频放入单独的通道中

enter image description here

使用amerge(或amix)和pan滤镜:

ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];[0:a][1:a]amerge=inputs=2,pan=stereo|c0<c0+c1|c1<c2+c3[a]" -map "[v]" -map "[a]"  output
  • 这里假设每个输入都包含立体声音频流。

使用一个特定输入的音频

此示例将使用来自 input1 的音频:

ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v]" -map "[v]" -map 1:a output

添加无声音频 / 如果一个输入没有音频

如果您混合具有音频和没有音频的输入,则amerge将失败,因为每个输入都需要音频。 您可以使用anullsrc过滤器添加无声音频以防止此问题:

ffmpeg -i input0 -i input1 -filter_complex "[0:v][1:v]vstack=inputs=2[v];anullsrc[silent];[0:a][silent]amerge=inputs=2[a]" -map "[v]" -map "[a]" -ac 2 output.mp4

3个视频或图片

这里输入图像描述

ffmpeg -i input0 -i input1 -i input2 -filter_complex "[0:v][1:v][2:v]hstack=inputs=3[v]" -map "[v]" output

如果你想垂直排列,请使用vstack而不是hstack。


2x2网格

输入图像描述

使用xstack

ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex "[0:v][1:v][2:v][3:v]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v]" -map "[v]" output

使用 hstackvstack

ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex "[0:v][1:v]hstack=inputs=2[top];[2:v][3:v]hstack=inputs=2[bottom];[top][bottom]vstack=inputs=2[v]" -map "[v]" output

使用xstack的语法更高效,但不如上面展示的方式易于理解。


带有文本的2x2网格

enter image description here

使用drawtext过滤器:

ffmpeg -i input0 -i input1 -i input2 -i input3 -filter_complex
"[0]drawtext=text='vid0':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v0];
 [1]drawtext=text='vid1':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v1];
 [2]drawtext=text='vid2':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v2];
 [3]drawtext=text='vid3':fontsize=20:x=(w-text_w)/2:y=(h-text_h)/2[v3];
 [v0][v1][v2][v3]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v]"
-map "[v]" output

4x4

使用xstack滤镜。总共16个视频的示例:

ffmpeg -i input0 -i input1 -i input2 -i input3 -i input4 -i input5 -i input6 -i input7 -i input8 -i input9 -i input10 -i input11 -i input12 -i input13 -i input14 -i input15 -i input16 -filter_complex "[0:v][1:v][2:v][3:v][4:v][5:v][6:v][7:v][8:v][9:v][10:v][11:v][12:v][13:v][14:v][15:v]xstack=inputs=16:layout=0_0|w0_0|w0+w1_0|w0+w1+w2_0|0_h0|w4_h0|w4+w5_h0|w4+w5+w6_h0|0_h0+h4|w8_h0+h4|w8+w9_h0+h4|w8+w9+w10_h0+h4|0_h0+h4+h8|w12_h0+h4+h8|w12+w13_h0+h4+h8|w12+w13+w14_h0+h4+h8" output.mp4

如果您需要先缩放输入:

ffmpeg -i input0 -i input1 -i input2 -i input3 -i input4 -i input5 -i input6 -i input7 -i input8 -i input9 -i input10 -i input11 -i input12 -i input13 -i input14 -i input15 -i input16 -filter_complex "[0:v]scale=iw/4:-1[v0];[1:v]scale=iw/4:-1[v1];[2:v]scale=iw/4:-1[v2];[3:v]scale=iw/4:-1[v3];[4:v]scale=iw/4:-1[v4];[5:v]scale=iw/4:-1[v5];[6:v]scale=iw/4:-1[v6];[7:v]scale=iw/4:-1[v7];[8:v]scale=iw/4:-1[v8];[9:v]scale=iw/4:-1[v9];[10:v]scale=iw/4:-1[v10];[11:v]scale=iw/4:-1[v11];[12:v]scale=iw/4:-1[v12];[13:v]scale=iw/4:-1[v13];[14:v]scale=iw/4:-1[v14];[15:v]scale=iw/4:-1[v15];[v0][v1][v2][v3][v4][v5][v6][v7][v8][v9][v10][v11][v12][v13][v14][v15]xstack=inputs=16:layout=0_0|w0_0|w0+w1_0|w0+w1+w2_0|0_h0|w4_h0|w4+w5_h0|w4+w5+w6_h0|0_h0+h4|w8_h0+h4|w8+w9_h0+h4|w8+w9+w10_h0+h4|0_h0+h4+h8|w12_h0+h4+h8|w12+w13_h0+h4+h8|w12+w13+w14_h0+h4+h8" output.mp4

调整/缩放输入

由于vstack需要两个视频具有相同的宽度,而hstack需要两个视频具有相同的高度,因此您可能需要缩放其中一个视频来匹配另一个视频:

简单的scale过滤器示例,将input0的宽度设置为640,并自动设置高度,同时保持纵横比:

ffmpeg -i input0 -i input2 -filter_complex "[0:v]scale=640:-1[v0];[v0][1:v]vstack=inputs=2" output

延迟/暂停视频

此示例将播放左上角的视频,并暂停其他视频。一旦左上角的视频结束,右上角的视频将播放,依此类推。

使用tpadadelayxstackamix滤镜:

ffmpeg -i top-left.mp4 -i top-right.mp4 -i bottom-left.mp4 -i bottom-right.mp4 -filter_complex "[1]tpad=start_mode=clone:start_duration=5[tr];[2]tpad=start_mode=clone:start_duration=10[bl];[3]tpad=start_mode=clone:start_duration=15[br];[0][tr][bl][br]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v];[1:a]adelay=5s:all=true[a1];[2:a]adelay=10s:all=true[a2];[3:a]adelay=15s:all=true[a3];[0:a][a1][a2][a3]amix=inputs=4[a]" -map "[v]" -map "[a]" output.mp4
  • 假设每个输入的持续时间为5秒。根据需要调整start_durationadelay值。

  • 此命令要求使用FFmpeg 4.3或更高版本。

  • 如果您不喜欢xstack的复杂度,可以像示例4:2x2网格中所示那样使用几个hstack/vstack。


1
ffmpeg 报告 No such filter: 'vstack'。我需要先安装它吗? - frans
1
@frans 你可能已经发现了,但是你的 ffmpeg 版本太旧了。建议用户使用从当前 git 主分支派生的 ffmpeg 构建版本。 - llogan
2
@RaduM,这是因为你的一个视频没有声音,你需要添加音频或静音音频。尝试使用两个带有音频的视频使用相同的命令,它会起作用。我发帖是因为今天我也遇到了同样的问题,并通过添加静音音频来纠正它。 - Jeffin
@Nasseh 在叠加这些视频之前,你需要使用更多的过滤器,比如缩放、裁剪和/或填充,使每个视频都相同。 - llogan
1
ffmpeg -i front.avi -i front.avi -i front.avi -i front.avi -i front.avi -i front.avi -filter_complex "[0:v][1:v][2:v]hstack=3[top];[3:v][4:v][5:v]hstack=3[bottom];[top][bottom]vstack[v]" -map "[v]" output.avi,但我无法打开avi文件。 - Kong
显示剩余21条评论

28

这个答案中提供的一种更简单的方法。


旧版本:
您可以使用FFmpeg中的padmovieoverlay过滤器来完成此操作。命令将类似于以下内容:

ffmpeg -i top.mov -vf 'pad=iw:2*ih [top]; movie=bottom.mov [bottom]; \
  [top][bottom] overlay=0:main_h/2' stacked.mov

首先,应该将要置顶的电影的高度加倍填充。然后加载底部电影。然后在填充顶部电影的一半偏移处叠加底部电影。


0

对于两个视频:

ffmpeg -i 1.mp4 -i 2.mp4 -filter_complex hstack out.mp4

更多视频(此示例中为3个):

ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -filter_complex hstack=3 out.mp4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接