我打算将大量不同格式和分辨率的视频文件拼接起来,有些没有声音,并在每个文件之间添加一个大约 0.5s 的短黑屏“暂停”。
我写了一个python脚本来生成这样的命令。
我使用 ffmpeg.exe -t 0.5 -f lavfi -i color=c=black:s=640x480 -c:v libx264 -tune stillimage -pix_fmt yuv420p blank500ms.mp4
创建了一个 0.5 秒的视频文件.
然后我用 -f lavfi -i anullsrc -c:v copy -c:a aac -shortest
添加了一个静音音频。
我现在遇到为没有流的流添加空白音轨的问题,但我不想生成新文件,我想将它添加到我的复杂过滤器中。
这是我的复杂脚本和生成命令。
命令(有行返回,因为我用 python 子进程模块发送这个)
ffmpeg.exe
-i
input0.mp4
-i
input1.mp4
-i
input2.mp4
-i
input3.mp4
-i
input4.mp4
-i
input5.mp4
-i
input6.mp4
-i
input7.mp4
-i
input8.mp4
-i
input9.mp4
-i
input10.mp4
-f
lavfi
-i
anullsrc
-filter_complex_script
C:/filter_complex_script.txt
-map
"[final_video]"
-map
"[final_audio]"
output.mp4
complex_filter_script:[0]fps=24[fps0];
[fps0]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled0];
[1]fps=24[fps1];
[fps1]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled1];
[2]fps=24[fps2];
[fps2]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled2];
[3]fps=24[fps3];
[fps3]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled3];
[4]fps=24[fps4];
[fps4]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled4];
[5]fps=24[fps5];
[fps5]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled5];
[6]fps=24[fps6];
[fps6]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled6];
[7]fps=24[fps7];
[fps7]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled7];
[8]fps=24[fps8];
[fps8]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled8];
[9]fps=24[fps9];
[fps9]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled9];
[10]fps=24[fps10];
[fps10]scale=480:270:force_original_aspect_ratio=decrease,pad=480:270:(ow-iw)/2:(oh-ih)/2,setsar=1,setpts=PTS-STARTPTS[rescaled10];
[10]split=10[blank0][blank1][blank2][blank3][blank4][blank5][blank6][blank7][blank8][blank9];
[rescaled0:v][0:a][blank0][rescaled1:v][1:a][blank1][rescaled2:v][2:a][blank2][rescaled3:v][3:a][blank3][rescaled4:v][4:a][blank4][rescaled5:v][5:a][blank5][rescaled6:v][11:a][blank6][rescaled7:v][11:a][blank7][rescaled8:v][11:a][blank8][rescaled9:v][11:a][blank9]concat=n=22:v=1:a=1[final_video][final_audio]
如您所见,有些视频使用[11:a]
,因为它是无声的音频流。input10.mp4,映射到 [10],然后拆分(或“克隆”)为 blanked0 到 9,是一个短暂停分隔符。
ffmpeg 告诉我错误
[Parsed_split_55 @ 000001591c33b280] Media type mismatch between the 'Parsed_split_55' filter output pad 1 (video) and the 'Parsed_concat_56' filter input pad 5 (audio)
[AVFilterGraph @ 000001591bf1e6c0] Cannot create the link split:1 -> concat:5
Error initializing complex filters.
Invalid argument
在使用 [X:Y:Z] 语法以及 concat 参数列表中的顺序如何重要时,我有点迷茫。我愿意接受任何其他建议来解决我的问题。我宁愿在一个命令中执行此操作,而不需要中间文件。
编辑:
有关详细信息,我已经编写了一个大型 concat+xstack 过滤器,它适用于 8GB 内存。
在这种情况下,有很多输入,但这些输入很小,大多数在 1 到 10MB 之间,所以它可能不会产生内存不足的问题,尽管我不确定。
最佳答案
虽然理论上可行,但我不建议使用这么多输入文件调用 FFmpeg。这将增加运行时的内存占用并可能会降低速度(如果没有引发内存不足错误)。相反,我的建议是分两步解决这个问题:
这里重要的部分是所有临时文件都具有完全相同的流配置。视频:编解码器、帧速率(
fps
)、pix_fmt(pfmt
)、大小(w
、h
),以及时基和音频:编解码器、sample_fmt(sfmt
)、采样率(fs
) , channel 布局('布局')和时基。 (我在花括号内的命令草图中使用了这些“变量”。)第 1 步命令草图:
下面我假设输入文件中的视频和音频配置是相同的,除了大小,您已经在代码中解决了这个问题。如果没有,您可能需要额外的过滤器。
ffmpeg -i input.mp4 \
-f lavfi -i color=c=black:s={w}x{h}:d=0.5:r={fps},format={pfmt} \
-f lavfi -i aevalsrc=0:n=1:c={layout}:s={fs},aformat={sfmt} \
-filter_complex [0:v]scale={w}:{h}:force_original_aspect_ratio=decrease,pad={w}:{h}:-1:-1,setsar=1[v]; \
[v][0:a][1:v][2:a]concat=n=2:v=1:a=1[vout][aout] \
-map [vout] -map [aout] -enc_time_base 0 output.mp4
ffmpeg -i input.mp4 \
-f lavfi -i color=c=black:s={w}x{h}:d=0.5:r={fps},format={pfmt} \
-f lavfi -i aevalsrc=0:n=1:c={layout}:s={fs},aformat={sfmt} \
-filter_complex [0:v]scale={w}:{h}:force_original_aspect_ratio=decrease,pad={w}:{h}:-1:-1,setsar=1[v]; \
[v][2:a][1:v][2:a]concat=n=2:v=1:a=1[vout][aout] \
-map [vout] -map [aout] -enc_time_base 0 output.mp4
请注意,1 和 2 之间的唯一区别是 concat
的第二个输入。筛选。如果音频丢失,只需使用 aevalsrc
对于丢失的流。带音频
ffmpeg -i input.mp4 \
-vf scale={w}:{h}:force_original_aspect_ratio=decrease,pad={w}:{h}:-1:-1,setsar=1 \
-enc_time_base 0 output.mp4
无音频:ffmpeg -i input.mp4 \
-f lavfi -i aevalsrc=0:n=1:c={layout}:s={fs},aformat={sfmt} \
-filter_complex [0:v]scale={w}:{h}:force_original_aspect_ratio=decrease,pad={w}:{h}:-1:-1,setsar=1[v]; \
[v][2:a]concat=n=1:v=1:a=1[vout][aout] \
-map [vout] -map [aout] -enc_time_base 0 output.mp4
ffprobe
识别文件是否有音频流(也可以使用ffmpeg,但我更喜欢这种方式):ffprobe -of default=nk=1:nw=1 -select_streams a -show_entries stream input.mp4
在 python 中,您可以使用 subprocess.run
运行此命令与 stdout=sp.PIPE
并检查获得的stdout
的长度字节(>0 有音频,=0 无音频)。ffconcat
文本文件。 The
concat
demuxer将文本文件作为输入,格式如下:ffconcat version 1.0
file output1.mp4
file output2.mp4
...
output#.mp4
是您在循环中生成的文件的名称。在步骤 1 循环中构建此文件并将其保存在与中间视频文件相同的目录中(称为 ffconcat.txt
)。第 2 步命令草图
大部分工作到此完成,您应该能够通过以下方式获得最终视频:
ffmpeg -i ffconcat.txt -c copy final.mp4
警告:我没有测试这些代码,所以如果你遇到任何你无法弄清楚的错字,请留下评论,我很乐意更正/澄清。一次性完成草图
上面写的内容可以扩展到单次运行(或部分组合)方法。假设有 100 个文件,那么你可以这样做:
ffmpeg -i input0.mp4 -i input1.mp4 ... -i input99.mp4 \
-f lavfi -i color=c=black:s={w}x{h}:d=0.5:r={fps},format={pfmt} \
-f lavfi -i aevalsrc=0:n=1:c={layout}:s={fs},aformat={sfmt} \
-filter_complex \
[0:v]scale={w}:{h}:force_original_aspect_ratio=decrease,pad={w}:{h}:-1:-1,setsar=1[v0]; \
[1:v]scale={w}:{h}:force_original_aspect_ratio=decrease,pad={w}:{h}:-1:-1,setsar=1[v1]; \
...
[99:v]scale={w}:{h}:force_original_aspect_ratio=decrease,pad={w}:{h}:-1:-1,setsar=1[v99]; \
[v0][0:a][100:v][101:a][v2][101:a][100:v][101:a]...[100:v][101:a][v99][99:a]concat=n=199:v=1:a=1[vout][aout] \
-map [vout] -map [aout] output.mp4
在这里,我假设第一个和最后一个有音频,第二个没有音频。输入 #100 = color
过滤器,输入 #101 = aevalsrc
筛选。要连接的视频-音频流对的总数为 199(100 个视频和 99 个 0.5 秒的暂停。这里的关键是您可以根据需要多次重复使用过滤器输出。
关于python - 我有一个 ffmpeg 命令来连接 300 多个不同格式的视频。 concat 复杂过滤器的正确语法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71992615/