Permalink
Browse files

Merge pull request #95 from eralpkaraduman/master

Added ability to merge multiple videos into one.
  • Loading branch information...
2 parents d3961ff + a4fdd12 commit 4bbf8f1892a12e85af7487f77053f9cbd5d37db3 @schaermu schaermu committed Dec 25, 2012
Showing with 140 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +27 −0 examples/mergeVideos.js
  3. +5 −0 lib/fluent-ffmpeg.js
  4. +107 −0 lib/processor.js
View
@@ -2,3 +2,4 @@
node_modules
lib-cov
*.swp
+.idea
View
@@ -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
@@ -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
@@ -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(){};

0 comments on commit 4bbf8f1

Please sign in to comment.