44

I want to join two mp4 files to create a single one. The video streams are encoded in h264 and the audio in aac. I can not re-encode the videos to another format due to computational reasons. Also, I cannot use any GUI programs, all processing must be performed with Linux command line utilities. FFmpeg cannot do this for mpeg4 files so instead I used MP4Box:

MP4Box -add video1.mp4 -cat video2.mp4 newvideo.mp4

Unfortunately the audio gets all mixed up. I thought that the problem was that the audio was in aac so I transcoded it in mp3 and used again MP4Box. In this case the audio is fine for the first half of newvideo.mp4 (corresponding to video1.mp4) but then their is no audio and I cannot navigate in the video also.

My next thought was that the audio and video streams had some small discrepancies in their lengths that I should fix. So for each input video I splitted the video and audio streams and then joined them with the -shortest option in FFmpeg.

Thus for the first video I ran:

 avconv -y -i video1.mp4 -c copy -map 0:0 videostream1.mp4
 avconv -y -i video1.mp4 -c copy -map 0:1 audiostream1.m4a
 avconv -y -i videostream1.mp4 -i audiostream1.m4a  -c copy -shortest  video1_aligned.mp4

Similarly for the second video and then used MP4Box as previously. Unfortunately this didn't work either. The only success I had was when I joined the video streams separately (i.e. videostream1.mp4 and videostream2.mp4) and the audio streams (i.e. audiostream1.m4a and audiostream2.m4a) and then joined the video and audio in a final file. However, the synchronization is lost for the second half of the video. Concretely, there is a 1 sec delay of audio and video. Any suggestions are really welcome.

llogan
  • 57,139
  • 15
  • 118
  • 145
Jose Armando
  • 441
  • 1
  • 4
  • 3
  • "FFmpeg cannot do this for mpeg4 files so instead I used MP4Box" do you mean MP4 file ? do both the audio-video streams uses same encoding parameters (width,height, SPS,PPS, framerate, samplingrate, number of channels ? –  Dec 18 '12 at 13:31
  • using ffprobe I see that the audio streams have identical attributes. The video streams have the same dimensions but different rates. For the 1st video Video: h264, 720x592, 277 kb/s, PAR 18944:12915 DAR 512:287, 24.97 fps, 45k tbr, 90k tbn, 90k tbc while for the second Video: h264, 720x592, 226 kb/s, PAR 481:330 DAR 39:22, 24.91 fps, 45k tbr, 90k tbn, 90k tbc . Do you believe that this is the source of my problems? –  Dec 18 '12 at 15:17
  • try this http://stackoverflow.com/questions/5415006/ffmpeg-combine-merge-multiple-mp4-videos-not-working – daya Dec 18 '12 at 16:37
  • Your question is already answered in ffmpeg FAQ: http://www.ffmpeg.org/faq.html#How-can-I-join-video-files_003f – Palec Dec 05 '13 at 16:26
  • MP4 supports joining video/audio with different characteristics using different track for different video, but player are not that smart. – rajneesh Dec 18 '12 at 16:13
  • just love those migrated questions that got later non migrated duplicates: http://stackoverflow.com/questions/18552901/how-to-merge-videos-by-avconv – Ciro Santilli OurBigBook.com Dec 03 '15 at 19:07
  • See also this even more-popular question: [Stack Overflow: How to concatenate two MP4 files using FFmpeg?](https://stackoverflow.com/q/7333232/4561887) – Gabriel Staples Nov 15 '22 at 23:04

7 Answers7

55

The best way to do this currently is with the concat demuxer. First, create a file called inputs.txt formatted like so:

file '/path/to/input1.mp4'
file '/path/to/input2.mp4'
file '/path/to/input3.mp4'

Then, simply run this ffmpeg command:

ffmpeg -f concat -i inputs.txt -c copy output.mp4

See also concatenation in ffmpeg FAQ.


I'm keeping the following here for the benefit of anyone using older versions of ffmpeg.

The latest versions of ffmpeg can do this: you'll have to remux the files into mpeg transport streams first (fairly processor-light, as it's only changing the container format):

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

If that throws up an error [1] about h264, you may need to use:

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf:v h264_mp4toannexb middle.ts

You'll have to do this separately with each input file. To concatenate the files together, use:

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy output.mp4

If that throws up an error about aac, you may need to use

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy -absf aac_adtstoasc output.mp4

If your system supports named pipes, you can do this without creating intermediate files.

mkfifo temp0 temp1

You'll have to do the following in three separate virtual terminals:

ffmpeg -i input0.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp0
ffmpeg -i input1.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp1
ffmpeg -f mpegts -i "concat:temp0|temp1" -c copy -absf aac_adtstoasc output.mp4

If output.mp4 already exists, the third ffmpeg will ask you whether you want to overwrite it, but it will do this after it has accessed the FIFOs, and this will make the first to ffmpegs close. So make sure that you choose an unused name for your output file.

This may not work if your input files are different - I believe that differences in bit rate are OK, but frame size, frame rate etc have to match up.

evilsoup
  • 13,097
  • 3
  • 59
  • 80
  • many thx mate, worked like a charm – Jose Armando Dec 26 '12 at 11:20
  • 2
    @DaveJarvis Not so; that's a message deliberately and maliciously spread by the libav team, who are a bunch of developers that split from the ffmpeg project to develop avconv (and changed the name because they couldn't secure the copyright on the ffmpeg name). See [Who can tell me the difference and relation between ffmpeg, libav, and avconv?](http://stackoverflow.com/questions/9477115/who-can-tell-me-the-difference-and-relation-between-ffmpeg-libav-and-avconv) for a bit more information. – evilsoup Nov 16 '13 at 14:29
  • 2
    `*** THIS PROGRAM IS DEPRECATED *** This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.` is a message I see now on running `ffmpeg` – Lord Loh. Feb 01 '14 at 22:11
  • @LordLoh. See the link in my previous comment. – evilsoup Feb 02 '14 at 11:32
  • 1
    That answer does not answer - how to concatenate mp4 with `avconv` – Lord Loh. Feb 02 '14 at 17:18
  • Comipled ffmpeg 2.2 as in this video: http://youtu.be/MRrGNIuLJ40 and then everythings works perfectly using the "-f concat -i inputfiles' options. +1 – qed Jun 01 '14 at 13:02
  • This also works for mkv files. – colton7909 Sep 18 '16 at 17:07
  • To expand on this, I had to search through a security camera filled with 30s clips for an event and used this command to generate the index file: `find ./ -name *.mp4 | sed -En "s/\.\/*(.*?)$/file '\1'/p" > inputs.txt` – Alan Samet Dec 23 '18 at 00:15
  • Keep in mind that neither exif-data nor GPS tracking information from original video clips will be copied – frist May 17 '19 at 12:06
  • Doesn't work for me: I get: `[concat @ 0x563ca0173700] Unsafe file name '/media/gabriel/3339-3730/record/20221113/18/31.mp4' inputs.txt: Operation not permitted` – Gabriel Staples Nov 15 '22 at 23:01
  • I figured it out and [added an answer here](https://stackoverflow.com/a/74454448/4561887). – Gabriel Staples Nov 16 '22 at 02:29
8

For mp4 the only working solution I found was with MP4Box from gpac package

#!/bin/bash
filesList=""
for file in $(ls *.mp4|sort -n);do
    filesList="$filesList -cat $file"
done
MP4Box $filesList -new merged_files_$(date +%Y%m%d_%H%M%S).mp4

or command is

MP4Box -cat file1.mp4 -cat file2.mp4 -new mergedFile.mp4

with mencoder and avconv I could'nt make it work :-(

Philippe Gachoud
  • 667
  • 7
  • 12
  • The command runs without apparent error (it just says creating track video+sound for file1.mp4 and then creating track sound for file2.mp4) .... and then I have no sound in the second part of the resulting video. mp4info says file1 has 1=video 2=audio, file2 has 1=audio, 2=video, maybe that's why... – David Faure Apr 06 '21 at 11:02
7

Here is a one-liner that makes it all that much easier. It does everything needed to be done in order to finally provide you with one resulting video file. Cheers!

find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > list.txt; ffmpeg -f concat -i list.txt -c copy output.mp4; rm list.txts
Anonymous
  • 179
  • 2
  • 5
  • There is a typo at the end... This may work in the current directory. If you use `find . -iname "*.mp4" | sort | sed 's:\ :\\\ :g'| sed 's/^/file /' > list.txt; ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4; rm list.txt` you can get files in subdirectories ... – jaromrax Mar 11 '21 at 14:58
2

On a Mac (macOS 10.13 High Sierra) I used the following with success:

for f in *.m4a; do echo "file '$f'" >> mylist.txt; done

Reorder as above similarly if necessary (note that the ./ was removed - the path was causing ffmpeg to throw the unsafe file name error).

Then I had to remove the codec and bitrate specified for the default MacPorts ffmpeg to like it:

ffmpeg -f concat -i mylist.txt  output.m4a
  • Welcome to Super User!, Please read the question again carefully. Your answer does not answer the original question which was about linux. If you believe that it will work on linux please add that so future readers have a clear understanding, other than that again welcome to superuser and thankyou for your input. Please take a couple of minutes and read:- http://superuser.com/help .Answering: http://superuser.com/help/how-to-answer. – mic84 Nov 14 '17 at 02:50
2

Thanks for the script dvo. It was a great starting point for me. I had no problem with using named pipes so I adapted the script to use them instead. Plus I fixed it to work with filenames with spaces in them. Output to named pipes does not "go" until you begin reading from them, hence the need to background the initial remux tasks with an & before the final call to avconv. Plus, don't forget to use -c copy, or you end up re-encoding the whole lot.

#!/bin/bash
for FILE in "$@"; do
   TAG=$(echo "$FILE" | sed -e s/[^A-Za-z0-9.]/_/g)
   mkfifo $TAG.mp4concatpipe
   avconv -loglevel "quiet" -i "$FILE"  -f mpegts -c copy -bsf h264_mp4toannexb -y $TAG.mp4concatpipe &
   IN=$IN\|$TAG.fifo
done

IN=${IN#\|}
avconv -i concat:$IN -c copy out.mp4
rm *.mp4concatpipe
Mark
  • 21
  • 2
  • For some reason this is giving me an "concat:first.m4v.fifo|second.m4v.fifo: No such file or directory" error.. even with quotes (-i concat:"$IN" or -i "concat:$IN"). MP4Box suggested in the other answer below however works great! – vorburger Aug 09 '14 at 13:16
  • Same error when I try it. I wonder if the ".fifo" on line 6 shouldn't be ".mp4concatpipe" instead? This fixes the error for me, but then I get another error. `Codec 'aac' (86018) is not supported by the bitstream filter 'h264_mp4toannexb'. Supported codecs are: h264 (27) ` – David Faure Apr 06 '21 at 10:50
1

Thanks evilsoup; here is a little script to automate the process, using the more recent avconv.
BTW, named pipes did not work for me (output to them got stuck).

   #!/bin/bash

    for FILE in $@; do
      avconv -i $FILE -map 0 -f mpegts -bsf h264_mp4toannexb -c:v copy -y $FILE.tmp
      IN=$IN\|$FILE.tmp
    done

    IN=${IN#\|}
    avconv -i concat:"$IN" out.mp4

    for FILE in $@; do
      rm $FILE.tmp
    done
dvo
  • 147
  • 3
1

Have enjoyed great success with

for f in ./*.m4a; do echo "file '$f'" >> mylist.txt; done

you may need to reorder mylist.txt slightly

ffmpeg -f concat -i mylist.txt -c:a libfdk_aac -b:a 128k output.m4a

ffmpeg version 2.2.3

Benjamin
  • 11
  • 2
  • I ran this without `-c:a libfdk_aac` and it worked. I tried installing a couple of packages for fdk aac on Ubuntu and it did not work. – Vasantha Ganesh Feb 12 '21 at 12:59