我正在尝试使用ffmpeg -f concat
。当我使用临时文件时,它可以工作。为了整洁,最好使用管道列表。我在较早的网络帖子中看到过这样的例子。它不再起作用了,还是我遗漏了一些显而易见的东西?这里有一个脚本说明了这个问题——如果你运行test.sh x
它,它会通过创建一个临时文件来工作。如果你运行,test.sh
那么 ffmpeg 就会失败。正如脚本注释中所述,我已经尝试过使用-safe 0
和-protocol_whiteflag "file,pipe,fd"
。
#!/bin/zsh
o=test.mp4
tmp=test.tmp
if [[ "$1" == "x" ]] ; then
echo Temp file $tmp...
ls GX01000?.mp4 | perl -ne 'print "file $_"' > $tmp
ffmpeg -hide_banner -y -f concat -i $tmp -c copy $o
else
echo Pipe
ls GX01000?.mp4 | perl -ne 'print "file $_"' | \
ffmpeg -hide_banner -y -f concat -i - -c copy $o
# this command line with -safe 0 and -protocol_whitelist doesn't work either
# ffmpeg -hide_banner -y -safe 0 -protocol_whitelist "file,pipe,fd" -f concat -i - -c copy $o
fi
以下是失败案例的输出:
% ./test.sh
Pipe
[fd @ 0x6000015f0620] Protocol 'fd' not on whitelist 'crypto,data'!
[concat @ 0x12e7055f0] Impossible to open 'fd:GX010005.mp4'
[in#0 @ 0x6000002f0100] Error opening input: Invalid argument
Error opening input file -.
Error opening input files: Invalid argument
谢谢!
这似乎有效:
它基于 @terdon 的回答。关键的区别在于,由于
$PWD
glob 表达式中的 ,文件列表中的文件名现在是绝对路径。它还在名称周围添加了单引号,如果完整路径包含任何空格,则这是必需的。显然,
ffmpeg
使用作为参数传递的文件的位置-i
作为列表中任何相对路径的目录。当您使用临时文件时,该文件与输入文件位于同一位置,因此它可以正常工作。当使用进程替换调用时,ffmpeg
将文件名视为类似于/dev/fd/12
,并假设所有相对文件名都引用了中的文件/dev/fd
。这种行为
ffmpeg
,嗯,很不寻常。我不知道是否有记录在案。本身不是管道,但由于您的目标是清洁,请考虑子 shell 文件重定向:
<(...)
调用进程替换,将子命令的输出视为 ffmpeg 可以直接读取的文件描述符,而无需任何特殊的内部逻辑来切换-
符号。编辑:使用 Gairfowl 的绝对路径技巧更新了原始子进程替换示例。
我们可以使用命名管道。
例子:
mkfifo list.txt
- 创建一个名为“list.txt”的命名管道。echo
命令将文件列表写入命名管道(使用完整路径)。echo
命令以&
在后台执行结束——这是必需的,因为写入命名管道是一个“阻塞操作”。ffmpeg -y -f concat -safe 0 -i list.txt -c copy output.mp4
- 从命名管道读取列表。最后,我们可以删除命名管道:
rm list.txt
。我在 Ubuntu 24.04 中使用 FFmpeg 7.1 测试了该示例
更新:
万一有人遇到问题...
根据接受的答案,使用完整文件路径可以解决问题。
在 Windows 终端中使用完整路径有效:
(echo file /Tmp/input1.mp4 && echo file /Tmp/input2.mp4) | ffmpeg -y -f concat -safe 0 -protocol_whitelist file,pipe -i pipe: -c copy output.mp4
在 Linux 终端中仍然存在一个问题(至少对于 FFmpeg 7.1 而言):
执行:
echo -e "file /home/rotem/Tmp/input1.mp4\nfile /home/rotem/Tmp/input2.mp4" | ffmpeg -y -f concat -safe 0 -protocol_whitelist file,pipe -i pipe: -c copy output.mp4
出现错误:
Impossible to open 'pipe:/home/rotem/Tmp/input1.mp4'
它看起来像是 FFmpeg 中的一个错误……
我真的很怀疑使用
-i -
在这里是否有效。-i
选项 e期望一个文件,而不是一个数据流,因此需要为其提供一些可以视为文件路径的东西:但是,如果您的 shell
bash
或任何其他支持进程替换的 shell,您可以将命令的输出作为文件提供:在您这样做时,请避免解析输出,
ls
因为这样很脆弱,很容易中断(在这种情况下,您可能不会遇到这种情况,因为您有一个简单的 glob,但最好习惯避免这样做)。您还应该引用变量(对于 zsh 来说不那么重要,但仍然是一个好主意)。以下是该命令的更强大版本: