python - 我有一个 ffmpeg 命令来连接 300 多个不同格式的视频。 concat 复杂过滤器的正确语法是什么?

标签 python powershell video ffmpeg

我打算将大量不同格式和分辨率的视频文件拼接起来,有些没有声音,并在每个文件之间添加一个大约 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。这将增加运行时的内存占用并可能会降低速度(如果没有引发内存不足错误)。相反,我的建议是分两步解决这个问题:

  • 第 1 步:对每个视频文件进行转码,以便按照您喜欢的方式正确编码。循环执行此操作并保存为中间文件。
  • 第 2 步:复制合并所有中间文件以形成最终输出

  • 这里重要的部分是所有临时文件都具有完全相同的流配置。视频:编解码器、帧速率(fps)、pix_fmt(pfmt)、大小(wh),以及时基和音频:编解码器、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对于丢失的流。
  • 最后一个输入视频没有 0.5 秒的填充:

  • 带音频
    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 无音频)。
  • 在运行每个输入的 ffmpeg 时,还要编写 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/

    相关文章:

    Python bdist_rpm -ba : unknown option error: command 'rpm' failed with exit status 1

    python - 如何从 wav 文件中获取 wav 样本?

    javascript - html5 视频缓冲区指示器

    python - 在 Python Pandas 中,如何搜索列元素是否包含前 2 位数字

    python - 子进程.Popen : mkvirtualenv not found

    powershell - Powershell v4 和 v5 之间 Join-Path cmdlet 的行为

    powershell - powershell 中的 Terraform state mv 命令使用带空格的名称失败

    powershell - 将AD组添加到多台服务器上的本地管理组的脚本

    video - 高级 ffmpeg 压缩控制

    batch-file - 批量或批量将 jpg 与音频文件相结合?