Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added ability to merge multiple videos into one. #95

Merged
merged 3 commits into from

2 participants

@eralpkaraduman

Based on concat: example here;
http://ffmpeg.org/faq.html#How-can-I-concatenate-video-files_003f

Creates intermediate files in input and output directories, but auto-deletes them after merge is finished.

Added an example also, and inculed ffmpeg commands which do the same acticton.

Requires a newer version of ffmpeg supporting "concat:" command.

I added no way to get progress information yet, but will.

@schaermu schaermu merged commit 4bbf8f1 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 18, 2012
  1. @eralpkaraduman
Commits on Dec 19, 2012
  1. @eralpkaraduman

    removed uuid dependency

    eralpkaraduman authored
  2. @eralpkaraduman

    ;(

    eralpkaraduman authored
This page is out of date. Refresh to see the latest.
View
1  .gitignore
@@ -2,3 +2,4 @@
node_modules
lib-cov
*.swp
+.idea
View
27 examples/mergeVideos.js
@@ -0,0 +1,27 @@
+var ffmpeg = require('../index');
+
+/*
+ replicates this sequence of commands:
+
+ ffmpeg -i title.mp4 -qscale:v 1 intermediate1.mpg
+ ffmpeg -i source.mp4 -qscale:v 1 intermediate2.mpg
+ ffmpeg -i concat:"intermediate1.mpg|intermediate2.mpg" -c copy intermediate_all.mpg
+ ffmpeg -i intermediate_all.mpg -qscale:v 2 output.mp4
+
+ Create temporary .mpg files for each video and deletes them after merge is completed.
+ These files are created by filename pattern like [videoFilename.ext].temp.mpg [outputFilename.ext].temp.merged.mp4
+ */
+
+var firstFile = "title.mp4";
+var secondFile = "source.mp4";
+var thirdFile = "third.mov";
+var outPath = "out.mp4";
+
+var proc = new ffmpeg({source:firstFile,nolog:true})
+ .mergeAdd(secondFile)
+ .mergeAdd(thirdFile)
+ //.mergeAdd(fourthFile)
+ //.mergeAdd(...)
+ .mergeToFile(outPath,function(){
+ console.log('files have been merged successfully');
+ });
View
5 lib/fluent-ffmpeg.js
@@ -59,6 +59,7 @@ function FfmpegCommand(args) {
inputfile: srcfile,
inputstream: srcstream,
timeout: timeout,
+ mergeList:[],
video: {},
audio: {},
additional: [],
@@ -201,6 +202,10 @@ function FfmpegCommand(args) {
this.options.additional.push(option, value);
return this;
};
+ FfmpegCommand.prototype.mergeAdd = function(path){
+ this.options.mergeList.push(path)
+ return this;
+ };
FfmpegCommand.prototype.toFormat = function(format) {
this.options.format = format;
View
107 lib/processor.js
@@ -105,6 +105,113 @@ exports = module.exports = function Processor(command) {
});
};
+ this.mergeToFile = function(targetfile,callback){
+ this.options.outputfile = targetfile;
+ var self = this;
+ var options = this.options;
+
+ var getExtension = function(filename) {
+ var ext = path.extname(filename||'').split('.');
+ return ext[ext.length - 1];
+ };
+
+ // creates intermediate copies of each video.
+ var makeIntermediateFile = function(_mergeSource,_callback){
+ var fname = _mergeSource+".temp.mpg";
+ var command = [
+ self.ffmpegPath,
+ [
+ '-i', _mergeSource,
+ '-qscale:v',1,
+ fname
+ ].join(' ')
+ ];
+ exec(command.join(' '),function(err, stdout, stderr) {
+ if(err)throw err;
+ _callback(fname);
+ });
+ };
+
+ // concat all created intermediate copies
+ var concatIntermediates = function(target,intermediatesList,_callback){
+ var fname = target+".temp.merged.mpg";
+
+ // unescape paths
+ for(var i=0; i<intermediatesList.length; i++){
+ intermediatesList[i] = unescapePath(intermediatesList[i]);
+ }
+
+ var command = [
+ self.ffmpegPath,
+ [
+ '-loglevel','panic', //Generetes too much muxing warnings and fills default buffer of exec. This is to ignore them.
+ '-i', 'concat:"'+intermediatesList.join("|")+'"',
+ '-c',"copy",
+ fname
+ ].join(' ')
+ ];
+ exec(command.join(' '), function(err, stdout, stderr) {
+ if(err)throw err;
+ _callback(fname);
+ });
+ };
+
+ var quantizeConcat = function(concatResult,numFiles,_callback){
+ var command = [
+ self.ffmpegPath,
+ [
+ '-i', concatResult,
+ '-qscale:v',numFiles,
+ targetfile
+ ].join(' ')
+ ];
+ exec(command.join(' '), function(err, stdout, stderr) {
+ if(err)throw err;
+ _callback();
+ });
+ }
+
+ var deleteIntermediateFiles = function(intermediates){
+ for(var i=0 ; i<intermediates.length ; i++){
+ fs.unlinkSync( unescapePath(intermediates[i]));
+ }
+ }
+
+ var unescapePath = function(path){
+ var f = path+"";
+ if(f.indexOf('"')==0)f = f.substring(1);
+ if(f.lastIndexOf('"')== f.length-1)f = f.substring(0, f.length-1);
+ return f;
+ }
+
+ if(options.mergeList.length<=0)throw new Error("No file added to be merged");
+ var mergeList = options.mergeList;
+ mergeList.unshift(options.inputfile)
+
+ var intermediateFiles = [];
+
+ async.whilst(function(){
+ return (mergeList.length != 0);
+ },function(callback){
+ makeIntermediateFile(mergeList.shift(),function(createdIntermediateFile){
+ if(!createdIntermediateFile)throw new Error("Invalid intermediate file");
+ intermediateFiles.push(createdIntermediateFile);
+ callback();
+ })
+ },function(err){
+ if(err)throw err;
+ concatIntermediates(targetfile,intermediateFiles,function(concatResult){
+ if(!concatResult)throw new Error("Invalid concat result file");
+ quantizeConcat(concatResult,intermediateFiles.length,function(){
+ intermediateFiles.push(concatResult); // add concatResult to intermediates list so it can be deleted too.
+ deleteIntermediateFiles(intermediateFiles);
+ callback(); // completed;
+ });
+ });
+ });
+
+ }
+
this.writeToStream = function(stream, callback) {
callback = callback || function(){};
Something went wrong with that request. Please try again.