50

I am trying to Merge two video without re-encoding them.

Currently i use a approach which is too much time consuming and resource as well. I just want to merge without re-encoding them. Currently i am using

        exec ( "cpulimit -l 90 ffmpeg -i $filename1 -qscale 0  $intermediate1 &> stream1.log" );
        exec ( "cpulimit -l 90 ffmpeg -i $filename2 -qscale 0  $intermediate2 &> stream2.log" );
        $output = '/var/www/html/myserver/merg/'.uniqid().'_merge.'.$ext;
        exec ( "cpulimit -l 90 cat $intermediate1 $intermediate2 | ffmpeg -i - -qscale 0 $output &> stream3.log" );

Above takes a lot of time.. I want a quick way to do it.

Yogesh Agarwal
  • 631
  • 1
  • 6
  • 8
  • By merging 2 videos, do you mean (1) concat one after the other ? or (2) mux both of them so they can co-exist in a single file ? (but cannot play both at the same time) , different requirements will lead to different solutions. – Ham Jul 15 '21 at 17:33

1 Answers1

106

Concatenation of files with same codecs:

There are two methods within ffmpeg that can be used to concatenate files of the same type: the concat demuxer & the concat protocol

The demuxer is more flexible – it requires the same codecs, but different container formats can be used; and it can be used with any container formats, while the concat protocol only works with a select few containers.

The concat demuxer instructions:

create a text file named vidlist.txt in the following format:

file '/path/to/clip1'
file '/path/to/clip2'
file '/path/to/clip3'

Note that these can be either relative or absolute paths.

Then issue the command:

ffmpeg -f concat -safe 0 -i vidlist.txt -c copy output

In case it's not abundantly clear, replace output with the video filename you wish to produce (whether that be output.mp4, output.mkv, output.avi) ffmpeg will utilize the container indicated by the extension.

The files will be stream copied in the order they appear in the vidlist.txt into the output container. the "copy codec" is blazing fast.

Edit: Note that although the docs say you don't need -safe 0 if the paths are relative, my testing indicates it's a requirement. It's possible that this may vary with your version of ffmpeg.

There are tips for auto generating the file available in the docs.

Note: All the clips must already exist or the command will fail because decoding won't start until the whole list is read.

The concat protocol instructions:

ffmpeg -i "concat:video1.ts|video2.ts|video3.ts" -c copy output.ts

Note: as mentioned above the concat protocol is severely limited in what streams and containers it supports so I never use it. The above is only included in an attempt to create a thorough answer. The concat demuxer is a far better choice for most projects.

An alternative suggestion: Personally I prefer using the Matroska container due to it's flexibility and low overhead and join videos with the same encoding using mkvmerge -o output.mkv input1.mkv + input2.mkv

Concatenation of files with different codecs:

If your clips don't use the same codecs for audio and video and/or have different rates, your stuck re-encoding to intermediate files prior to joining which as we all know is both time and resource consuming.

Note that special characters can break things so if you have these in your filenames you'll need to deal with them.

Sources: Experience

https://ffmpeg.org/ffmpeg-formats.html

Elder Geek
  • 1,425
  • 2
  • 14
  • 18
  • FYI, it'll explode if you have ' in your file name. I guess it doesn't realize 3 single quotes means one is in the filename. – Katastic Voyage Apr 26 '18 at 19:56
  • @KatasticVoyage odd characters in filenames aren't recommended. However hey can be [dealt with](https://stackoverflow.com/questions/15783701/which-characters-need-to-be-escaped-in-bash-how-do-we-know-it) – Elder Geek Apr 27 '18 at 00:45
  • I got `Unable to find a suitable output format for 'output' output: Invalid argument`. Appending a recognizable extension to `output` like `output.mp4` solved the problem. – Michał Lepczyński Mar 17 '20 at 02:05
  • @MichałLepczyński Thanks for sharing. – Elder Geek Mar 20 '20 at 16:21
  • 7
    `ffmpeg -f concat -i vidlist.txt -c copy out.mp4` works for me – Aryeh Beitz Apr 19 '20 at 21:19
  • 3
    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:11
  • @Salem Please see the Alternative solution part of the answer that refers to mkvmerge. Despite the name mkvmerge can also produce mp4 files. – Elder Geek Jul 30 '20 at 17:21
  • @ElderGeek I already tried both solution if I put more than 2 file they get corrupted . – Salem Jul 31 '20 at 13:22
  • I'm confused - if `mkvmerge` also requires files of the same encoding, what advantage does it have over the `concat` protocol? Or have I misread? – Hashim Aziz Mar 03 '21 at 01:26
  • 1
    @HashimAziz Ok, now I'm confused! I'm not sure how alternative became synonymous with advantageous. To be clear, I'm not saying that an alternative approach that works is in any way superior to any other approach that also works. At that point it's a matter of preference as the end result is reached regardless. Cheers! – Elder Geek Sep 02 '21 at 19:37
  • 1
    @Salem I know it's a while back, but... I just ran an `mkvmerge -o output.mkv file1.mp4 + file2.mp4 + file3.mp4 + file4.mp4`, and the resulting file was the concatenation of all four inputs. So, that **should** work unless there's some other issue. A good test would be to try `mkvmerge -o part1.mkv file1.mp4 + file2.mp4; mkvmerge -o part2.mkv file2.mp4 + file3.mp4; mkvmerge -o part3.mkv file3.mp4 + file4.mp4` — if any of those three "part" files comes out damaged, then that's where the problem is. – FeRD Nov 13 '21 at 14:36
  • How would you use the `concat` demuxer option WITHOUT creating an intermediate file? – Raleigh L. Jul 27 '22 at 02:36
  • 1
    @RaleighL. I'm sorry, I don't understand your question as it pertains to my answer, as I don't believe that I stated that you COULD! Feel free to ask a new question of the community, and perhaps someone will have a solution that meets your rather strict requirements. Cheers! – Elder Geek Aug 23 '22 at 21:18
  • 1
    @ElderGeek My question was a direct follow-up to your answer specifically -- you gave an example of using the concat demuxer with an intermediate file to concatenate MP4 files, I merely asked if there was a way to do exactly that, but without creating an intermediate file; that doesn't warrant its own standalone question. – Raleigh L. Aug 24 '22 at 03:11
  • 1
    @RaleighL. Apologies for any confusion. In answer to your follow up question, I have no idea how you might accomplish that, and thought perhaps someone else might (as I find it difficult to believe that anything is impossible) hence my suggestion of a new question, perhaps something along the lines of "how can I avoid using an intermediate file?" I would assume you might be able to craft something using an pipe, but I never thought that using an intermediate file was an onerous task to be avoided. Cheers! – Elder Geek Sep 11 '22 at 15:57
  • `ffmpeg -f concat -safe 0 -i <(printf "file '/tmp/video5358008758.mp4'\nfile '/tmp/video6358008758.mp4'") -c copy /tmp/out.mp4` works for me. File list can be manually changed. Command worked only with `-safe 0`. – ilyazub May 24 '23 at 09:12
  • @ilyazub thank you for sharing! All I can say is the commands I posted worked for me back when I posted it. Since you appear to have an alternate approach, feel free to provide another answer! Cheers! – Elder Geek May 25 '23 at 15:47
  • Answer with bash for loop to generate such a file https://stackoverflow.com/a/66928788/720763 – joseph_morris Aug 06 '23 at 16:45