9

How to concatenate (join) multiple MP4 video files into one file interactively?

There are a lot of programs that do this for two files from the command line. For instance:

  • ffmpeg
  • avconv
  • MP4Box

But we frequently need a solution to do this interactively.

Anthon
  • 78,313
  • 42
  • 165
  • 222
Slyx
  • 3,845
  • 2
  • 19
  • 25
  • 1
    Can you describe what you mean by interactive? – slm Feb 20 '14 at 04:50
  • @slm I mean a program who asks the user to enter the input files one by one, then the output file to create. and then make the concatenation. – Slyx Feb 20 '14 at 04:57
  • I've never seen a program that does this directly, it's as you've crafted, a shell script that collects the info and then assembles the command-line. Are you looking for improvements over what you have? – slm Feb 20 '14 at 05:06
  • @slm i posted this because it's a frequent need for multimedia users like me. So I hope it helps someone else. Of course any improvements are more than welcome ! – Slyx Feb 20 '14 at 05:18
  • Would be nice if you also explained what you mean by **obsolete**, since [ffmpeg is not that](http://en.wikipedia.org/wiki/Ffmpeg#History) ...so -1 but I'll be happy to change my downvote *if you remove the fallacious information.* – goldilocks Feb 20 '14 at 15:31
  • 1
    @gold I put an edit in the queue. `ffmpeg` is indeed by *no means* dead or obsolete: The last `git` commit to `master` was [15 minutes ago](http://git.videolan.org/?p=ffmpeg.git) and I use it daily. – Anko - inactive in protest Feb 20 '14 at 15:46
  • @goldilocks, `ffmpeg` is **depricated**, its team (Libav developers) say "This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.". I edited my Q to add this information. – Slyx Feb 21 '14 at 19:09
  • You should provide a source for information of that kind -- as in an actual reference, not just an "according to me someone else said". **In any case, it's still incorrect.** `avconv` is part of the libav project which is *[a fork of ffmpeg](http://en.wikipedia.org/wiki/Avconv#Fork_from_FFmpeg)*. These are now two separate and distinct but both very much widely used and alive projects; the comments you found are dated and I believe were included in *a Debian packaging* of ffmpeg at one point. But **ffmpeg is no more or less "obsolete" than libav and vice versa.** – goldilocks Feb 22 '14 at 01:39
  • @goldilocks, indeed after visiting [ffmpeg website](http://www.ffmpeg.org/) i discovered that it's still active and there are many recent updates. The product is not obsolete! I did the necessary edit to my Q. Thanks ! – Slyx Feb 28 '14 at 10:13

2 Answers2

8

I haven't tried this method recently but don't see why it wouldn't still work. I believe you can just cat .mp4 files together if you don't want to do anything other than concatenate them.

1. Using cat

$ cat file1.mp4 file2.mp4 > file3.mp4
$ ffmpeg -i file3.mp4 -qscale:v 2 output.avi

I still use ffmpeg all the time, it too can concatenate files.

2. Using ffmpeg

  1. Make a list of files to concatenate

    $ cat inputs.txt 
    file sample_mpeg4.mp4
    file sample_mpeg4.mp4
    
  2. concatenate

    $ ffmpeg -f concat -i inputs.txt -c copy out.mp4
    
    $ ll |grep -E "sample|out"
    -rw-rw-r--. 1 saml saml 491860 Feb 19 23:36 out.mp4
    -rw-r--r--. 1 saml saml 245779 Feb 19 23:32 sample_mpeg4.mp4
    

    Other methods are covered in the FFmpeg wiki: How to concatenate (join, merge) media files.

    NOTE: Ubuntu does not appear to support the concat format. You have to use the concat protocol. In addition, it has per stream codec options. Thus, using the concat protocol results as follows:

    $ ffmpeg -i input1.mp4 -vcodec copy -acodec copy \
         -vbsf h264_mp4toannexb -f mpegts intermediate1.ts
    
    $ ffmpeg -i input2.mp4 -vcodec copy -acodec copy \
         -vbsf h264_mp4toannexb -f mpegts intermediate2.ts
    
    $ ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" \
         -vcodec copy -acodec copy -absf aac_adtstoasc output.mp4
    

    Ubuntu ffmpeg options are documented here.

slm
  • 363,520
  • 117
  • 767
  • 871
  • Interesting ! I didn't know that `cat` is enough for MP4 files ! the solution is not interactive though ! – Slyx Feb 20 '14 at 04:58
  • @Slyx - yeah that's why I asked what you meant by interactive. Let me see what you said about it and see what I can add to this. Check that `cat` works though. The last time I used it it was with `.mpg` files and it def. worked with those. – slm Feb 20 '14 at 05:03
  • 2
    I verified that. Using `cat` is not a valid solution. The generated file by `cat`ing two file only shows the content of the first input file! – Slyx Feb 20 '14 at 05:16
  • @Slyx - cat works but the timestamps are not correct, so when you attempt to play it back the video player is getting confused by the jump in timestamp from 00 to the end, then back to 00. If you were to transcode the video this would get fixed as part of that process. There are ways to regenerate the timestamps as well. – slm Feb 20 '14 at 05:22
  • 1
    That's what i mean too. The two contents are there but the media player just detects the first one. – Slyx Feb 20 '14 at 05:24
  • @Slyx - here's the scoop: http://unix.stackexchange.com/questions/43896/is-it-possible-to-merge-video-files-using-cat – slm Feb 20 '14 at 05:33
  • That's it! I edited your answer to include the format correction. – Slyx Feb 20 '14 at 05:49
4

I use MP4Box as work base.
The script i suggest reads all the files one by one, verifying each one (weather it's an ordinary file), asks the user for the input filename to create.

#!/bin/bash
printf "###  Concatenate Media files ###\n"
fInputCount=0
# Reading input files
IFS=''
while (true)
do
    let currentNumber=$fInputCount+1 
    printf "File n°%s (\"ok\" to finish): " $currentNumber
    read inputFile
    [ "$inputFile" == "ok" ] && break
    [ ! -e "$inputFile" ] || [ ! -f "$inputFile" ] && printf "\"%s\" : Invalid filename. Skipped !\n" "$inputFile" && continue
    ((fInputCount++))
    inputFileList[$fInputCount]=$inputFile
    printf "\"%s\" : Added to queue !\n" "$inputFile"
done
[ "$fInputCount" == "0" ] || [ "$fInputCount" == "1" ] && echo "No enough input data. BYE ! " && exit
# Listing the input file list 
for ((i=1;i<=$fInputCount;i++))
do
    printf "%2d : %s\n" $i ${inputFileList[$i]}
done
# Reading the output filename
while (true)
do
    printf "Output file without extention (\"none\" to dismiss) : "
    read outputRead
    [ "$outputRead" == "none" ] && echo "Dismissed. BYE ! " && exit
    [ "$outputRead" == "" ] && echo "Try again ! " && continue
    [ -e "$outputRead" ] && echo "\"$outputRead\" exists. Try again !" && continue
    outputFile=$outputRead.mp4
    echo "Output to \"$outputFile\". Go !" && break
done
# Creating a random temporary filename
tmpOutFile="/tmp/concatMedia"`date +"%s%N"| sha1sum | awk '{print $1}'`".mp4"
# Joining the two first input files
MP4Box -cat "${inputFileList[1]}" -cat "${inputFileList[2]}" $tmpOutFile
# Adding all other files
for ((i=3;i<=$fInputCount;i++))
do
    tmpIntermediateFile=$tmpOutFile
    tmpOutFile="/tmp/concatMedia"`date +"%s%N"| sha1sum | awk '{print $1}'`".mp4"
    MP4Box -cat $tmpIntermediateFile -cat "${inputFileList[$i]}" $tmpOutFile
    rm $tmpIntermediateFile
done
mv $tmpOutFile "$outputFile"
# Finished
echo "\"$outputFile\" Saved !"
Slyx
  • 3,845
  • 2
  • 19
  • 25