Permalink
Browse files

Added ability to merge videos & created an example

  • Loading branch information...
1 parent bd5a6aa commit 2b1b48414a7b137b5b8c2176a43fe087b90316b7 @eralpkaraduman eralpkaraduman committed Dec 18, 2012
Showing with 140 additions and 1 deletion.
  1. +1 −0 .gitignore
  2. +23 −0 examples/mergeVideos.js
  3. +5 −0 lib/fluent-ffmpeg.js
  4. +110 −0 lib/processor.js
  5. +1 −1 package.json
View
@@ -2,3 +2,4 @@
node_modules
lib-cov
*.swp
+.idea
View
@@ -0,0 +1,23 @@
+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
+ */
+
+var firstFile = "title.mp4";
+var secondFile = "source.mp4"
+var outPath = "out.mp4"
+var tempFolderPath = "myTempFolder/"; // requires a temp folder to store intermediate videos, deletes them after merge is completed.
+
+var proc = new ffmpeg({source:firstFile,nolog:true})
+ .mergeAdd(secondFile)
+ //.mergeAdd(thirdFile)
+ //.mergeAdd(fourthFile)
+ .mergeToFile(outPath,tempFolderPath,function(){
+ console.log('files has been merged succesfully');
+ });
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
@@ -5,6 +5,7 @@ var fs = require('fs'),
exec = require('child_process').exec,
spawn = require('child_process').spawn,
Registry = require('./registry'),
+ uuid = require('node-uuid'),
exports = module.exports = function Processor(command) {
// constant for timeout checks
@@ -105,6 +106,115 @@ exports = module.exports = function Processor(command) {
});
};
+ this.mergeToFile = function(targetfile,tempFolderPath,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 = uuid.v1()+".mpg";
+ var fullP = self.escapedPath(path.join(tempFolderPath, fname), true);
+ var command = [
+ self.ffmpegPath,
+ [
+ '-i', _mergeSource,
+ '-qscale:v',1,
+ fullP
+ ].join(' ')
+ ];
+ exec(command.join(' '),function(err, stdout, stderr) {
+ if(err)throw err;
+ _callback(fullP);
+ });
+ };
+
+ // concat all created intermediate copies
+ var concatIntermediates = function(intermediatesList,_callback){
+ var fname = uuid.v1()+".mpg";
+ var fullP = self.escapedPath(path.join(tempFolderPath, fname), true);
+
+ // 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",
+ fullP
+ ].join(' ')
+ ];
+ exec(command.join(' '), function(err, stdout, stderr) {
+ if(err)throw err;
+ _callback(fullP);
+ });
+ };
+
+ 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(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(){};
View
@@ -10,7 +10,7 @@
},
"repository": "git://github.com/schaermu/node-fluent-ffmpeg.git",
"devDependencies": { "mocha": "latest", "should": "latest" },
- "dependencies": { "winston": ">=0.5.10" },
+ "dependencies": { "winston": ">=0.5.10","node-uuid":"1.4.0" },
"engines" : { "node" : ">=0.5.0" },
"main": "index",
"scripts": {

0 comments on commit 2b1b484

Please sign in to comment.