如何使用FFMPEG将文件夹中的所有视频合并为一个单独的视频文件

31
我有一个包含20个以上视频文件的文件夹,我需要将它们合并成一个长的视频文件。如何使用Python中的FFMPEG实现这一点?
我知道以下命令:
ffmpeg -vcodec copy -isync -i \ "concat:file1.mp4|file2.mp4|...|fileN.mp4" \

输出文件为outputfile.mp4。

但是我不想手动输入20多个文件的名字。

7个回答

44

这就是我最终使用的...

find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > fl.txt; ffmpeg -f concat -i fl.txt -c copy output.mp4; rm fl.txt

这个东西很丑,但好像运行得还不错,并且可以处理文件名中的空格。此外,我不确定为什么楼主要问关于Python的事情——当一些肮脏的旧Bash / sed可以解决问题时,没有必要使用像Python这样可爱的东西!;)

附言:我知道这是一个旧帖子,但如果谷歌搜索“ffmpeg concat”把我带到这里,它可能也会把其他可怜的灵魂带到这里。请注意,上述方法可能仅在所有文件具有相同设置/编解码器时起作用。

附言2:@Stackdave说他曾经用这个东西删除了他的视频文件夹!我真的不知道那是怎么发生的,而且自那以后我也没有收到任何投诉,但是像往常一样,当您从互联网上复制和粘贴随机的Bash片段时,请三思而后行!


3
我用你的脚本删除了文件夹视频中的所有文件!警告。 - stackdave
4
很遗憾听到这个消息,戴夫! https://www.reddit.com/r/ProgrammerHumor/comments/7u92m8/i_installed_the_chrome_owo_extension_to_force/ - Roger Heathcote

23

可以是一行的Bash命令:

for f in *.mp4 ; do echo file \'$f\' >> list.txt; done && ffmpeg -f concat -safe 0 -i list.txt -c copy stitched-video.mp4 && rm list.txt

确保所有视频文件的帧大小和音视频编解码器完全相同。

否则,您在连接它们时可能需要进行转换:

for f in *.mp4 ; do echo file \'$f\' >> list.txt; done && ffmpeg -f concat -safe 0 -i list.txt -s 1280x720 -crf 24 stitched-video.mp4 && rm list.txt

感谢llogan。已修复。 - Gaurang Arora
这对我有效。将其转换并与第二个命令连接始终是安全的。谢谢。 - Dami
谢谢! 我有一些视频列表,像video-1.mp4,video-2.mp4,video-10.mp4...,这些文件需要排序。这里有一个版本可以按混合字符串和数字对文件进行排序:rm list.txt; for f in *.mp4 ; do echo file \'$f\' >> list.txt; done && sort -V list.txt > list-sort.txt && ffmpeg -f concat -safe 0 -i list-sort.txt -c copy stitched-video.mp4 ; rm list.txt list-sort.txt - soywiz

11

这里是一个Windows批处理文件,用于将目录中所有的.avi文件连接起来:

for %%f in (*.avi) do (
    echo file %%f >> list.txt
)
ffmpeg -f concat -safe 0 -i list.txt -c copy output.avi
del list.txt

请查看ffmpeg文档中的Concatenate部分


很不幸,我正在处理的文件名中有空格。echo file "%%f" >> list.txt 不够用了。一旦遇到第一个空格字符,cmd就会停止。 - gimmegimme
2
NVM,以下内容有所帮助:https://superuser.com/questions/1574718/ffmpeg-wont-work-if-filename-has-spaces。使用单引号而不是双引号,echo file '%%f' >> list.txt,然后在for函数块之后且在语句“ffmpeg -f concat -safe...”之前,将以下语句放置在其自己的一行上,sed -i "s/"/'/g" list.txt。 - gimmegimme

8
请使用以下内容:
cat *.mp4  | ffmpeg  -i pipe: -c:a copy -c:v copy all.mp4

另一种解决方案:

创建一个像这样的文本文件:

mylist.txt

file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

并使用ffmpeg拼接:

ffmpeg -f concat -i mylist.txt -c copy all.mp4

more infos


4
Windows不工作。 - Billy

2
如果ffmpeg不支持*.mp4文件,您可以使用以下方法替换文件列表;
ls -1 *.mp4 | perl -0pe 's/\n/|/g;s/\|$//g'

但我认为你的例子没有遵循规范,所以你可能需要这样做:

for F in *.mp4 ; do
    ffmpeg -i $F -c copy -bsf:v h264_mp4toannexb -f mpegts $(echo $F | perl -pe 's/mp4$/ts/g');
done
ffmpeg -i "concat:$(ls -1 *.ts | perl -0pe 's/\n/|/g;s/\|$//g')" -c copy -bsf:a aac_adtstoasc outputfile.mp4

还可以参考类似的问题


1
或者只需使用 echo *.mp4 | tr ' ' '|',如果您的文件名中没有空格。 - Dietrich Epp

0

我知道原问题是关于Python的,但当我询问某个问题时,谷歌把我带到了这里,实际上我不记得确切的查询内容。

首先,文件应该具有以下格式:

file 'filename1.mp4'
file 'filename2.mp4' 
file 'filename3.mp4'

等等。

接下来,Java(Mac)的解决方案:

public static void joinVideos(String folderPath) throws Exception {
    File folderFile = new File(folderPath);
    //File[] files = folderFile.listFiles();
    //On Mac filter out .DS_Store
    File[] files = folderFile.listFiles(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return !name.equals(".DS_Store");
        }
    });
    StringBuilder fileListBuilder = new StringBuilder();
    for (File file : files) {
        fileListBuilder.append("file '").append(file.getName()).append("'\n");
    }
    ReadWriteUtil.writeTxt(fileListBuilder.toString(), folderPath + File.separator + "list.txt");

    ProcessBuilder processBuilder = new ProcessBuilder("/usr/local/bin/ffmpeg", "-f", "concat", "-i", "list.txt", "-c", "copy", "output.mp4");
    File errorFile = new File(folderPath + File.separator + "error.txt");
    processBuilder.redirectError(errorFile);

    Process process = processBuilder.directory(new File(folderPath)).start();

    int exitCode = process.waitFor();
    String error = ReadWriteUtil.readFileAsString(errorFile);
    System.out.println("error: " + error);
    System.out.println("VideoJoiner Finished with exit code: " + exitCode);
    System.out.println("videos joined");

}

0

Windows操作系统解决方案:

  1. 在目标文件夹中打开cmd.exe
  2. 粘贴并运行以下代码
chcp 65001
(for %i in (*.mp4) do @echo file '%i') > my_video_list.txt
ffmpeg -safe 0 -f concat -i my_video_list.txt -c copy output.mp4


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