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.

  • 1
    Can you describe what you mean by interactive? – slm Feb 20 '14 at 4: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 4: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 5: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 5:18
  • 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 and I use it daily. – Anko Feb 20 '14 at 15:46

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.

  • Interesting ! I didn't know that cat is enough for MP4 files ! the solution is not interactive though ! – Slyx Feb 20 '14 at 4: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 5:03
  • 2
    I verified that. Using cat is not a valid solution. The generated file by cating two file only shows the content of the first input file! – Slyx Feb 20 '14 at 5: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 5:22
  • 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 5:24
up vote 4 down vote accepted

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 !"

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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