29

I have a folder with 20+ video files and I need to merge them to make one long video file. How can I achieve this using FFMPEG in Python?

I know the following command

ffmpeg -vcodec copy -isync -i \ "concat:file1.mp4|file2.mp4|...|fileN.mp4" \

outputfile.mp4

But I'd rather not type all the names of the 20+ files.

X_1
  • 323
  • 1
  • 4
  • 6

7 Answers7

43

This is what I've ended up using...

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

It's ugliness pains me but it seems to work ok and it handles spaces in the file names. Also, not sure why OP was asking about python - no need to use something lovely like python when some dirty old bash/sed will do the trick! ;)

ps: I know this is an old post but if googling "ffmpeg concat" brought me here it will probably bring other poor souls here too. Note the above will probably only work if all your files have the same settings/codecs.

pps: @Stackdave says he managed to delete his video folder with this back in the day! I've really no idea how that could have happened and I've had no complaints since but as always when copying and pasting randomish snippets of bash you found on the internet Caveat Emptor!

Roger Heathcote
  • 3,091
  • 1
  • 33
  • 39
22

can be a single line bash command:

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

make sure all video files are exactly the same frame size and audio-video codecs.

Else you may convert them while concatenating:

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
Gaurang Arora
  • 321
  • 2
  • 4
  • Thanks llogan. Fixed. – Gaurang Arora Aug 06 '19 at 22:16
  • This works for me. Always safe to convert and concat with second command. Thank You. – Dami May 05 '20 at 05:18
  • Thanks! I had a list of videos like `video-1.mp4`, `video-2.mp4`, `video-10.mp4`..., and the files needed to be sorted. Here a version sorting the files with mixed strings a numbers: ```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 Jan 25 '21 at 22:02
11

Here's a Windows batch file to concatenate all .avi files in a directory:

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

See Concatenate in ffmpeg docs.

lexicore
  • 42,748
  • 17
  • 132
  • 221
  • Thank unfortunately, the file i'm dealing with has spaces in it's file name. echo file "%%f" >> list.txt was not enough. cmd stops once it encounters the first space character. – gimmegimme Apr 24 '21 at 17:32
  • 2
    NVM, the following helped, https://superuser.com/questions/1574718/ffmpeg-wont-work-if-filename-has-spaces . Instead of double quotes, use single quote, echo file '%%f' >> list.txt, then after the for function block AND before the statement "ffmpeg -f concat -safe...", place the following statement on its own line, sed -i "s/\"/'/g" list.txt – gimmegimme Apr 24 '21 at 18:03
7

Use this:

cat *.mp4  | ffmpeg  -i pipe: -c:a copy -c:v copy all.mp4

Another solution:

create a text file like this:

mylist.txt

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

and use ffmpeg concat:

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

more infos

Abdes
  • 926
  • 1
  • 15
  • 27
2

If ffmpeg won't like the *.mp4 you can just do this in place of the file list;

ls -1 *.mp4 | perl -0pe 's/\n/|/g;s/\|$//g'

but I think your example is not following specification, so you may want this:

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

also see this similar question

Community
  • 1
  • 1
user1133275
  • 2,642
  • 27
  • 31
0

I know that original question is about Python, but Google have brought me here, when I asked about.. actually I don't remember exact query.

First, file should have following format:

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

and so on.

And next, solution in 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");

}
Yuriy N.
  • 4,936
  • 2
  • 38
  • 31
0

Windows OS solution:

  1. Open cmd.exe in destination folder
  2. Paste and run this code
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

antonshc
  • 1
  • 2