44

I can successfully join multiple files using the following command:

ffmpeg -f concat -i input.txt -codec copy output.mp4

The only problem with this command is that you need to read the filepaths from the text file called input.txt with the following content:

file 'C:\Users\fabio\Downloads\Super\Sharks\01.mp4'
file 'C:\Users\fabio\Downloads\Super\Sharks\02.mp4'
file 'C:\Users\fabio\Downloads\Super\Sharks\03.mp4'

Is there a way to achieve the same goal without having to read the filepaths from a file? I have tried the following with no luck:

ffmpeg -f concat -i file "C:\a\b\01.mp4" file "C:\a\b\02.mp4" -codec copy output.mp4
ffmpeg -f concat -i "C:\a\b\01.mp4" "C:\a\b\02.mp4" -codec copy output.mp4

Do I have to use a different command?

1

7 Answers 7

55

2019 Update:

As mentioned in the comments, Stack Overflow has a great description of the available options for concatenation, as well as a discussion of which method to use depending on the types of files you're using:

How to concatenate two MP4 files using FFmpeg?

Original 2016 Answer:

You should be able to use the concat protocol method to combine the files:

ffmpeg -i "concat:input1.mp4|input2.mp4|input3.mp4" -c copy output.mp4

In addition, the FFmpeg manual discusses a method specifically for MP4 files, in order to losslessly concatenate them, but requires that you create temporary files (or named pipes):

ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts
ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" -c copy -bsf:a aac_adtstoasc output.mp4
15
  • 1
    First command worked for me like a butter..it took 2 to 3 seconds to concat my 6 mp4 files into output file (239 MB approx). Dec 16, 2016 at 10:39
  • 43
    The first command didn't work for me. It just copied the first file. Jun 11, 2017 at 1:32
  • 11
    This doesn't work, it just copied the first file to output.mp4.
    – crmpicco
    Nov 14, 2018 at 14:01
  • 4
    File-level concatenation does not work for MP4, so the concat protocol is not recommended for this format and will generally not work.
    – llogan
    Feb 21, 2019 at 18:23
  • 1
    @brasofilo Thank you for the link. This is long overdue, but I updated the answer to point people in that direction. Feb 22, 2019 at 16:11
10

You may replace file with list by outputting list to stdout and reading the list from stdin by ffmpeg:

(echo file 'a.mp4' & echo file 'b.mp4') | ffmpeg -protocol_whitelist file,pipe -f concat -safe 0 -i pipe: -vcodec copy -acodec copy "result.mp4"
6
  • Using ffmpeg version 2.4.3-tessus on Mac OS 10.12.6, this just throws an error: "Unrecognized option 'protocol_whitelist'". Without the protocol_whitelist option, it seems to just make a copy of the second MP4 file.
    – James
    Jun 20, 2019 at 18:53
  • @ErmanKadirKahraman, singleline form is fine for both windows and linux, but trailing \ makes it correct only for linux as windows uses ^ as escaping for linebreak.
    – Qwertiy
    Jun 11, 2020 at 13:26
  • @ErmanKadirKahraman, buy the way, I'm not sure if it works in linux at all as its echo file 'a.mp4' prints file a.mp4 when on windows it keeps apostrophe file 'a.mp4'.
    – Qwertiy
    Jun 11, 2020 at 13:31
  • 3
    This is best answer I found after search for hours , it even works on shell script .
    – Salem F
    Jul 1, 2020 at 19:33
  • 1
    I also liked this best. I posted a 'script' based on this idea. Aug 8, 2020 at 1:29
2

No, there appears to be no way to use the ffmpeg concat demuxer on a single command line without some hack. You need to create the input text file with the list of files. I thought this strange myself, maybe someone will add this to FFMpeg at a later date.

The accepted answer to this question uses the concat protocol, not the concat demuxer which is what the OP asked.

2
  • 1
    Actually there is. stdin.
    – Qwertiy
    Feb 21, 2019 at 9:11
  • concat protocol shouldn't be used with MP4 or any other format the requires a global header.
    – llogan
    Sep 18, 2019 at 19:00
2

Without external text file, one line command to merge all MP4 files in a folder:

in CMD (the Command Prompt):

(FOR /R %A IN (*.mp4) DO @ECHO file '%A') | ffmpeg -protocol_whitelist file,pipe -f concat -safe 0 -i pipe: -vcodec copy -acodec copy "Videos_Merged.mp4"

in a BATch file:

(FOR /R %%A IN (*.mp4) DO @ECHO file '%%A') | ffmpeg -protocol_whitelist file,pipe -f concat -safe 0 -i pipe: -vcodec copy -acodec copy "Videos_Merged.mp4"

P.S.: CHCP 65001 command need if the directory contains unicode characaters.

(This code based Qwertiy's one-line command. I'm again grateful to Qwertiy for the informations in his reply. So I fixed the code.

3
  • Not sure that you need dir command - for hase some forms that iterate filenames. Also a questionable moment is order of files - I'm not sure whether it sorts the list somehow or not.
    – Qwertiy
    Jan 11, 2021 at 17:05
  • @Qwertiy , thanks for the code and your reply. Actually, your're right. FOR %G IN (*.mp4) Do @echo %G - It lists MP4s properly. I recorded a few some videos today. Filenames: VID_20210706_170844.mp4 ... VID_20210706_174446.mp4 This code doesn't work: (FOR %A IN (*.mp4) DO @ECHO file '%A') | ffmpeg -protocol_whitelist file,pipe -f concat -safe 0 -i pipe: -vcodec copy -acodec copy "Videos_Merged.mp4" I updated the last properly working code in my post.
    – pureocean
    Jul 6, 2021 at 19:53
  • Yep, nice. Already upvoted the answer last time.
    – Qwertiy
    Jul 6, 2021 at 22:59
1

You could still do it in a script without changing the command. Something like:

echo "file fname1" >$$.tmp    #single redirect creates or truncates file
echo "file fname2" >>$$.tmp   # double redirect appends
echo "file fname3" >>$$.tmp   # do as many as you want.

ffmpeg -f concat -i $$.tmp -codec copy output.mp4

rm $$.tmp  # just to clean up the temp file. 
           # For debugging, I usually leave this out.

The $$ expands to the pid of the shell running the command, so the file name will be different every time you run it. so you could use $$.txt if you prefer. Or something else...

Also, you can use here files to add a bunch of data to the file:

cat <<EOF >$$.tmp
file fname1
file fname2
file fname3
EOF

bash Variable substitution works, so you can programatically determine the content of the file, it doesn't have to be fixed. I embed this sort of stuff in for loops all the time. Finally, the redirect works the same as above, so >$$.tmp truncates then writes, >>$$.tmp appends.

1
  • 2
    The question asks, "is there a way to achieve the same goal without having to read the filepaths from a file?"  All you have done is provide a way to write the filepaths to a file (prior to reading the filepaths from the file).  This does not answer the question. Feb 13, 2017 at 0:01
1

I also liked Qwertiy's answer best. Here is a script (works for an arbitrary number of files, also for .mov; tested on macOS):

#!/bin/bash

if [ $# -lt 1 ]; then
    echo "Usage: `basename $0` input_1.mp4 input_2.mp4 ... output.mp4"
    exit 0
fi

ARGS=("$@") # determine all arguments
output=${ARGS[${#ARGS[@]}-1]} # get the last argument (output file)
unset ARGS[${#ARGS[@]}-1] # drop it from the array
(for f in "${ARGS[@]}"; do echo "file '$f'"; done) | ffmpeg -protocol_whitelist file,pipe -f concat -safe 0 -i pipe: -vcodec copy -acodec copy $output
1

GoPro 'chapters' are footage around 4 GB - The camera starts a new file every ~ 10 minutes. If you have media files with exactly the same codec and codec parameters you can concatenate them quite easily. Fastest way, that I found, is use ffmpeg with concating function:

ffmpeg -f concat -safe 0 -i <(for f in *.MP4; do echo "file '$PWD/$f'"; done) -c copy output.mp4

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.