55

Here is the command I am using to combine multiple videos:

ffmpeg -i 75_540_38HQ2.mp4 -i 76_70_20.mp4 -i 76_173_80.mp4 -i 81_186_35.mp4 -vcodec copy -acodec copy Mux1.mp4

The resulting Mux1.mp4 does not contain all videos. Only the first video (75_540_38HQ2.mp4). The file size of the source and resulting video is below (as you can see, resulting video is slightly larger than first vid):

$ ls -lh
-rw-r--r-- 1 dbaker dbaker  42M 2011-03-24 11:59 75_540_38HQ2.mp4
-rw-r--r-- 1 dbaker dbaker 236M 2011-03-24 12:09 76_173_80.mp4
-rw-r--r-- 1 dbaker dbaker  26M 2011-03-24 12:05 76_70_20.mp4
-rw-r--r-- 1 dbaker dbaker  54M 2011-03-24 12:15 81_186_35.mp4
-rw-r--r-- 1 dbaker dbaker  44M 2011-03-24 14:48 Mux1.mp4

Here is the output of the ffmpeg command. To me it looks ok, showing the multiple source inputs and the single output.

FFmpeg version SVN-r26402, Copyright (c) 2000-2011 the FFmpeg developers
  built on Mar 21 2011 18:05:32 with gcc 4.4.5
  configuration: --enable-gpl --enable-version3 --enable-nonfree --enable-postproc --enable-libfaac --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libxvid --enable-x11grab
  libavutil     50.36. 0 / 50.36. 0
  libavcore      0.16. 1 /  0.16. 1
  libavcodec    52.108. 0 / 52.108. 0
  libavformat   52.93. 0 / 52.93. 0
  libavdevice   52. 2. 3 / 52. 2. 3
  libavfilter    1.74. 0 /  1.74. 0
  libswscale     0.12. 0 /  0.12. 0
  libpostproc   51. 2. 0 / 51. 2. 0
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '75_540_38HQ2.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    creation_time   : 1970-01-01 00:00:00
    encoder         : Lavf52.93.0
  Duration: 00:00:29.99, start: 0.000000, bitrate: 11517 kb/s
    Stream #0.0(eng): Video: h264, yuv420p, 1280x960 [PAR 1:1 DAR 4:3], 11575 kb/s, 29.94 fps, 29.97 tbr, 30k tbn, 59.94 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
    Stream #0.1(eng): Audio: aac, 48000 Hz, stereo, s16, 127 kb/s
    Metadata:
      creation_time   : 1970-01-01 00:00:00
Input #1, mov,mp4,m4a,3gp,3g2,mj2, from '76_70_20.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    creation_time   : 1970-01-01 00:00:00
    encoder         : Lavf52.93.0
  Duration: 00:00:19.98, start: 0.000000, bitrate: 10901 kb/s
    Stream #1.0(eng): Video: h264, yuv420p, 1280x960 [PAR 1:1 DAR 4:3], 10804 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
    Stream #1.1(eng): Audio: aac, 48000 Hz, stereo, s16, 128 kb/s
    Metadata:
      creation_time   : 1970-01-01 00:00:00
Input #2, mov,mp4,m4a,3gp,3g2,mj2, from '76_173_80.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    creation_time   : 1970-01-01 00:00:00
    encoder         : Lavf52.93.0
  Duration: 00:03:09.99, start: 0.000000, bitrate: 10393 kb/s
    Stream #2.0(eng): Video: h264, yuv420p, 1280x960 [PAR 1:1 DAR 4:3], 10321 kb/s, 29.96 fps, 29.97 tbr, 30k tbn, 59.94 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
    Stream #2.1(eng): Audio: aac, 48000 Hz, stereo, s16, 128 kb/s
    Metadata:
      creation_time   : 1970-01-01 00:00:00

Seems stream 0 codec frame rate differs from container frame rate: 119.88 (120000/1001) -> 30000.00 (30000/1)
Input #3, mov,mp4,m4a,3gp,3g2,mj2, from '81_186_35.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    creation_time   : 1970-01-01 00:00:00
    encoder         : Lavf52.93.0
  Duration: 00:00:35.00, start: 0.000000, bitrate: 12700 kb/s
    Stream #3.0(eng): Video: h264, yuv420p, 1280x720 [PAR 1:1 DAR 16:9], 12620 kb/s, 59.91 fps, 30k tbr, 60k tbn, 119.88 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
    Stream #3.1(eng): Audio: aac, 48000 Hz, stereo, s16, 128 kb/s
    Metadata:
      creation_time   : 1970-01-01 00:00:00
Output #0, mp4, to 'Mux1.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    creation_time   : 1970-01-01 00:00:00
    encoder         : Lavf52.93.0
    Stream #0.0(eng): Video: libx264, yuv420p, 1280x960 [PAR 1:1 DAR 4:3], q=2-31, 11575 kb/s, 30k tbn, 29.97 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
    Stream #0.1(eng): Audio: libfaac, 48000 Hz, stereo, 128 kb/s
    Metadata:
      creation_time   : 1970-01-01 00:00:00
Stream mapping:
  Stream #0.0 -> #0.0
  Stream #2.1 -> #0.1
Press [q] to stop encoding
frame=  883 fps=632 q=-1.0 Lsize=   44730kB time=29.40 bitrate=12465.1kbits/s    
video:41678kB audio:2969kB global headers:0kB muxing overhead 0.184548%

Am I doing something blindingly stupid here?

The source videos came from a video camera, and are small snippets taken with ffmpeg -i bigfile.mp4 -ss 20 -t 10 -vcodec copy etc..

Thanks heaps!! Dave


Edit: couldn't solve it so I just use avidemux GUI tool. It seemed to append the MP4's just fine.

Must be a problem with MP4's or just the ones that come off a gopro camera.

dtbaker
  • 3,267
  • 4
  • 23
  • 29
  • If I try multiple combinations of the videos I get the same result. eg: only Input0 and Input1. It always results in an output containing the first video. – dtbaker Mar 24 '11 at 05:08
  • 1
    See also http://stackoverflow.com/questions/7333232/concatenate-two-mp4-files-using-ffmpeg/11175851#11175851 and http://trac.ffmpeg.org/wiki/Concatenate – rogerdpack Mar 10 '15 at 15:11
  • 2
    Not all files allow the three methods. For example you can't use concat as a protocol with MP4 files. Use concat as a filter to avoid re-encoding: https://trac.ffmpeg.org/wiki/Concatenate – Smeterlink Dec 08 '17 at 10:31

10 Answers10

25

Assuming you want to concatenate the movie, you can use the following command:

ffmpeg -f concat -i inputs.txt -vcodec copy -acodec copy Mux1.mp4

With the following text in inputs.txt:

file 75_540_38HQ2.mp4 
file 76_70_20.mp4 
file 76_173_80.mp4
file 81_186_35.mp4

Note: some distributions (like Ubuntu) do not have ffmpeg in their repository and instead define ffmpeg to be an alias of avconv. This won't work with avconv, so in such a case you have to compile ffmpeg yourself. You can check whether you have the real ffmpeg by running ffmpeg and checking if the first output line ends with "the FFmpeg developers".

bcmpinc
  • 2,772
  • 26
  • 32
  • How to issue that command without the text file ! I need to run it from command line or script directly . – Salem Jul 01 '20 at 19:10
  • 1
    You can try using `-i -` or `-i /dev/stdin` and then pipe the list of files in on standard input. Or use named pipes or a temporary file. If you need more help, post a question. – bcmpinc Jul 03 '20 at 04:08
13

Forget about FFmpeg, use MP4Box instead, it is easy and faster:

    mp4box -add video1.mp4 -cat video2.mp4 -cat video3.mp4 output.mp4

It is available for Windows, Linux and OS X: http://www.videohelp.com/tools/mp4box

If you are on Windows you can use YAMB which is a GUI for MP4Box that works great: http://www.videohelp.com/tools/YAMB

UPDATE Jun-2016: FFmpeg has added a concatenation filter, more info here: https://stackoverflow.com/a/11175851/218418

Community
  • 1
  • 1
Rodrigo Polo
  • 3,257
  • 2
  • 21
  • 29
7

From the ffmpeg man page "Examples" section:

You can put many streams of the same type in the output:

ffmpeg -i test1.avi -i test2.avi -vcodec copy -acodec copy \
       -vcodec copy -acodec copy test12.avi -newvideo -newaudio

In addition to the first video and audio streams, the resulting output file test12.avi will contain the second video and the second audio stream found in the input streams list.

The "-newvideo", "-newaudio" and "-newsubtitle" options have to be specified immediately after the name of the output file to which you want to add them.

If you meant you want to concatenate them, the FAQ has instructions.

I'm not sure if this question/answer belongs on SuperUser.

David Pope
  • 6,099
  • 2
  • 33
  • 45
  • 7
    -newvideo, -newaudio, -newsubtitle have been removed from the current version. You have to use the -map option. (which I haven't wrapped my brain around.) If somebody wants to show how to use -map to string together MP4s that would be awesome. – Phil Glau Jul 11 '12 at 19:43
  • 2
    These docs describe the concat filter and how to use the -map option in that case: http://ffmpeg.org/trac/ffmpeg/wiki/How%20to%20concatenate%20(join,%20merge)%20media%20files – Frank Schwieterman Jul 08 '13 at 18:45
  • Note I'm having videos get corrupted if I concat very long files, so I'm going to try to mp4->mpeg then use simple concat. – Frank Schwieterman Jul 08 '13 at 18:46
  • The concat option in ffmpeg does not require the use of the -map option if you are really just concatenating the input files (e.g. you have two mp4 files, each 2 minutes in duration, and want to create a single mp4 file of 4 minutes duration as the output). The ffmpeg command line in Windows 7 (using bcmpinc's "inputs.txt" file, see above) is: ffmpeg -f concat -i inputs.txt -c copy output.mp4 – Ed999 Mar 05 '17 at 15:25
6

You have to convert them into an MPEG format that can be easily concatenated. Below is a script I use and call "ffcat" for my GoPro videos. It essentially runs several "ffmpeg -i" commands which produce concatenate-able MPEG, which is piped to an ffmpeg command that then converts them to an H.264 mp4 file.

It also sizes the videos to 720p but you may not want that.

The "h264options" are flags I recently found on the internet at h264.code-shop.com

Hope this helps, Reid


cmd="( "

h264options="-vcodec libx264 -b 512k -flags +loop+mv4 -cmp 256 \
 -partitions +parti4x4+parti8x8+partp4x4+partp8x8+partb8x8 \
 -me_method hex -subq 7 -trellis 1 -refs 5 -bf 3 \
 -flags2 +bpyramid+wpred+mixed_refs+dct8x8 -coder 1 -me_range 16 \
   -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10\
 -qmax 51 -qdiff 4"

outfile="out-`date +%F-%H%M.%S`.mp4"

for i; do
    cmd="${cmd}ffmpeg -i $i -ab 256000 -vb 10000000 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -f mpeg -; "
done
cmd="${cmd} ) | ffmpeg -y -i - -threads 8 ${h264options} -vb 10000000 -acodec libfaac -ar 44100 -ab 128k -s 1280x720 ${outfile}"
echo "${cmd}"
eval ${cmd}
Reid Ellis
  • 3,852
  • 1
  • 19
  • 16
  • 6
    This has the negative effect of transcoding the video twice. I can imagine you might have to transcode once but twice shouldn't be necessary. – Dan Pritts Dec 24 '12 at 22:13
  • 4
    MP4 files do not need to be converted into an MPEG format before being concatenated. In order to do the most simple concatenation, where all the input files are mp4 and the output file is also mp4, no transcoding is needed at all. The ffmpeg command line in Windows 7 (using bcmpinc's inputs.txt file, see below) is: ffmpeg -f concat -i inputs.txt -c copy output.mp4 – Ed999 Mar 05 '17 at 15:15
5

Simple concat works for mp4 and mkv files if all the input videos have the same codec and you want output video also in same codec. https://trac.ffmpeg.org/wiki/Concatenate
you need to creat a text file like

# this is a comment
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

And then use command

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

I have used the example from the same reference page, it works pretty well. The only issue comes when video is not properly captured. It might introduce audio video sync issues because it just copies the PTS and DTS information from the source videos to the destination video.
To get a full proof solution you need to read video packet-by-packet and then put together all the packets in one video with customized optimizations like dropping repeating PTS packets and maintaining monotonic PTS values.

Satyam Naolekar
  • 492
  • 6
  • 10
3

I have been using this script quite successfully. The results are perfect because it is using raw video.

http://trac.ffmpeg.org/wiki/How%20to%20concatenate%20%28join,%20merge%29%20media%20files

Make sure you edit the EXTRA OPTIONS string.

#!/bin/bash

################################################################################
#
# Script name: MultiMedia Concat Script (mmcat)
# Author: burek (burek021@gmail.com)
# License: GNU/GPL, see http://www.gnu.org/copyleft/gpl.html
# Date: 2012-07-14
#
# This script concatenates (joins, merges) several audio/video inputs into one
# final output (just like as if all the inputs were played in a playlist, one
# after another).
#
# All input files must have at least one audio and at least one video stream.
# If not, you can easily add audio silence, using FFmpeg. Just search the
# internet for "ffmpeg add silence".
#
# The script makes use of FFmpeg tool (www.ffmpeg.org) and is free for use under
# the GPL license. The inspiration for this script came from this FAQ item:
# http://ffmpeg.org/faq.html#How-can-I-join-video-files_003f
#
# If you find any bugs, please send me an e-mail so I can fix it.
#
################################################################################
#
# General syntax: mmcat <input1> <input2> <input3> ... <output>
#
# For example: mmcat file1.flv file2.flv output.flv
# would create "output.flv" out of "file1.flv" and "file2.flv".
#
################################################################################

# change this to what you need !!!
EXTRA_OPTIONS='-vcodec libx264 -crf 23 -preset medium -acodec aac -strict experimental -ac 2 -ar 44100 -ab 128k'

################################################################################
#
# NO NEED TO TOUCH ANYTHING AFTER THIS LINE!
#
################################################################################

# the version of the script
VERSION=1.3

# location of temp folder
TMP=/tmp

################################################################################

echo "MultiMedia Concat Script v$VERSION (mmcat) - A script to concatenate multiple multimedia files."
echo "Based on FFmpeg - www.ffmpeg.org"
echo "Don't forget to edit this script and change EXTRA_OPTIONS"
echo ""

################################################################################
# syntax check (has to have at least 3 params: infile1, infile2, outfile
################################################################################
if [ -z $3 ]; then
    echo "Syntax: $0 <input1> <input2> <input3> ... <output>"
    exit 1
fi

################################################################################
# get all the command line parameters, except for the last one, which is output
################################################################################
# $first  - first parameter
# $last   - last parameter (output file)
# $inputs - all the inputs, except the first input, because 1st input is
#           handled separately
################################################################################
first=${@:1:1}
last=${@:$#:1}
len=$(($#-2))
inputs=${@:2:$len}

# remove all previous tmp fifos (if exist)
rm -f $TMP/mcs_*

################################################################################
# decode first input differently, because the video header does not have to be
# kept for each video input, only the header from the first video is needed
################################################################################
mkfifo $TMP/mcs_a1 $TMP/mcs_v1

ffmpeg -y -i $first -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a1 2>/dev/null </dev/null &
ffmpeg -y -i $first -an -f yuv4mpegpipe -vcodec rawvideo $TMP/mcs_v1 2>/dev/null </dev/null &

# if you need to log the output of decoding processes (usually not necessary)
# then replace the "2>/dev/null" in 2 lines above with your log file names, like this:
#ffmpeg -y -i $first -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a1 2>$TMP/log.a.1 </dev/null &
#ffmpeg -y -i $first -an -f yuv4mpegpipe -vcodec rawvideo $TMP/mcs_v1 2>$TMP/log.v.1 </dev/null &

################################################################################
# decode all the other inputs, remove first line of video (header) with tail
# $all_a and $all_v are lists of all a/v fifos, to be used by "cat" later on
################################################################################
all_a=$TMP/mcs_a1
all_v=$TMP/mcs_v1
i=2
for f in $inputs
do
    mkfifo $TMP/mcs_a$i $TMP/mcs_v$i

    ffmpeg -y -i $f -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a$i 2>/dev/null </dev/null &
    { ffmpeg -y -i $f -an -f yuv4mpegpipe -vcodec rawvideo - 2>/dev/null </dev/null | tail -n +2 > $TMP/mcs_v$i ; } &

    # if you need to log the output of decoding processes (usually not necessary)
    # then replace the "2>/dev/null" in 2 lines above with your log file names, like this:
    #ffmpeg -y -i $f -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a$i 2>$TMP/log.a.$i </dev/null &
    #{ ffmpeg -y -i $f -an -f yuv4mpegpipe -vcodec rawvideo - 2>$TMP/log.v.$i </dev/null | tail -n +2 > $TMP/mcs_v$i ; } &

    all_a="$all_a $TMP/mcs_a$i"
    all_v="$all_v $TMP/mcs_v$i"
    let i++
done

################################################################################
# concatenate all raw audio/video inputs into one audio/video
################################################################################
mkfifo $TMP/mcs_a_all
mkfifo $TMP/mcs_v_all
cat $all_a > $TMP/mcs_a_all &
cat $all_v > $TMP/mcs_v_all &

################################################################################
# finally, encode the raw concatenated audio/video into something useful
################################################################################
ffmpeg -f u16le -acodec pcm_s16le -ac 2 -ar 44100 -i $TMP/mcs_a_all \
       -f yuv4mpegpipe -vcodec rawvideo -i $TMP/mcs_v_all \
    $EXTRA_OPTIONS \
    $last

################################################################################
# remove all fifos
################################################################################
rm -f $TMP/mcs_*
denjello
  • 521
  • 2
  • 12
3

Concat demuxer

The concat demuxer was added to ffmpeg 1.1. If your version of ffmpeg is to old, get the newest static binary from here: http://www.ffmpeg.org/download.html

Instructions

Create a file mylist.txt with all the files you want to have concatenated in the following form (Lines starting with a dash are ignored):

# this is a comment
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

Note that these can be either relative or absolute paths. Then you can encode your files with:

ffmpeg -f concat -i mylist.txt -c copy output

It is possible to generate this list file with a bash for loop, or using printf. Either one of the following would generate a list file containing every *.wav in the working directory:

for f in ./*.wav; do echo "file '$f'" >> mylist.txt; done
printf "file '%s'\n" ./*.wav > mylist.txt

Source: ffmpeg wiki

Community
  • 1
  • 1
erik
  • 2,058
  • 1
  • 21
  • 30
1

As found here, you have a few options:

1. concat protocol:

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

2. concat filter:

this one I don't fully understand, you probably need to look at all the diagrams and filter graphs, but it lets you deal with multiple formats and differing codec properties

    ffmpeg -i input1.mp4 -i input2.webm -i input3.mov \
-filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[outv][outa]" \
-map "[outv]" -map "[outa]" output.mkv

3. concat demuxer:

First, you need to generate a list file of some sort, eg. "mylist.txt"

    # this is a comment
    file '/path/to/file1.wav'
    file '/path/to/file2.wav'
    file '/path/to/file3.wav'

Second, you need to run a command to use the list

ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.wav
jjisnow
  • 799
  • 7
  • 4
0

MP4Box does work without breaking the audio. I did the following to obtain good results:

  1. Download the latest Linux deb build from the gpac web site: http://gpac.wp.mines-telecom.fr/downloads/gpac-nightly-builds/

  2. Use the -force-cat option

Sample command line:

MP4Box -force-cat -add in1.mp4 -cat in2.mp4 -cat in3.mp4 ... out.mp4

Some minor comments:

  1. The above way is important, as the latest version of MP4Box distributed with Linux Mint 13 is buggy, and does result in corrupted audio.

  2. -force-cat is important, as the video format tag was changed from AVC to avc3 without it.

rayryeng
  • 96,704
  • 21
  • 166
  • 177
numberer6
  • 111
  • 1
  • 1
0

You can avoid explicitly creating a list file and do the whole thing in a single line

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

Refer to ffmpeg wiki.

LF00
  • 22,077
  • 20
  • 117
  • 225