1
0
mirror of https://github.com/musix-org/musix-oss synced 2024-12-23 16:13:18 +00:00
musix-oss/node_modules/ffmpeg/lib/video.js
2020-03-03 22:30:50 +02:00

863 lines
28 KiB
JavaScript

var fs = require('fs')
, path = require('path')
, when = require('when');
var errors = require('./errors')
, presets = require('./presets')
, utils = require('./utils');
module.exports = function (filePath, settings, infoConfiguration, infoFile) {
// Public info about file and ffmpeg configuration
this.file_path = filePath;
this.info_configuration = infoConfiguration;
this.metadata = infoFile;
// Commands for building the ffmpeg string conversion
var commands = new Array()
, inputs = new Array()
, filtersComlpex = new Array()
, output = null;
// List of options generated from setting functions
var options = new Object();
/*****************************************/
/* FUNCTION FOR FILL THE COMMANDS OBJECT */
/*****************************************/
/**
* Add a command to be bundled into the ffmpeg command call
*/
this.addCommand = function (command, argument) {
// Check if exists the current command
if (utils.in_array(command, commands) === false) {
// Add the new command
commands.push(command);
// Add the argument to new command
if (argument != undefined)
commands.push(argument);
} else
throw errors.renderError('command_already_exists', command);
}
/**
* Add an input stream
*/
this.addInput = function (argument) {
inputs.push(argument);
}
/**
* Add a filter complex
*/
this.addFilterComplex = function (argument) {
filtersComlpex.push(argument);
}
/**
* Set the output path
*/
var setOutput = function (path) {
output = path;
}
/*********************/
/* SETTING FUNCTIONS */
/*********************/
/**
* Disables audio encoding
*/
this.setDisableAudio = function () {
if (options.audio == undefined)
options.audio = new Object();
// Set the new option
options.audio.disabled = true;
return this;
}
/**
* Disables video encoding
*/
this.setDisableVideo = function () {
if (options.video == undefined)
options.video = new Object();
// Set the new option
options.video.disabled = true;
return this;
}
/**
* Sets the new video format
*/
this.setVideoFormat = function (format) {
// Check if the format is supported by ffmpeg version
if (this.info_configuration.encode.indexOf(format) != -1) {
if (options.video == undefined)
options.video = new Object();
// Set the new option
options.video.format = format;
return this;
} else
throw errors.renderError('format_not_supported', format);
}
/**
* Sets the new audio codec
*/
this.setVideoCodec = function (codec) {
// Check if the codec is supported by ffmpeg version
if (this.info_configuration.encode.indexOf(codec) != -1) {
if (options.video == undefined)
options.video = new Object();
// Set the new option
options.video.codec = codec;
return this;
} else
throw errors.renderError('codec_not_supported', codec);
}
/**
* Sets the video bitrate
*/
this.setVideoBitRate = function (bitrate) {
if (options.video == undefined)
options.video = new Object();
// Set the new option
options.video.bitrate = bitrate;
return this;
}
/**
* Sets the framerate of the video
*/
this.setVideoFrameRate = function (framerate) {
if (options.video == undefined)
options.video = new Object();
// Set the new option
options.video.framerate = framerate;
return this;
}
/**
* Sets the start time
*/
this.setVideoStartTime = function (time) {
if (options.video == undefined)
options.video = new Object();
// Check if time is a string that contain: hours, minutes and seconds
if (isNaN(time) && /([0-9]+):([0-9]{2}):([0-9]{2})/.exec(time)) {
time = utils.durationToSeconds(time);
} else if (!isNaN(time) && parseInt(time) == time) {
time = parseInt(time, 10);
} else {
time = 0;
}
// Set the new option
options.video.startTime = time;
return this;
}
/**
* Sets the duration
*/
this.setVideoDuration = function (duration) {
if (options.video == undefined)
options.video = new Object();
// Check if duration is a string that contain: hours, minutes and seconds
if (isNaN(duration) && /([0-9]+):([0-9]{2}):([0-9]{2})/.exec(duration)) {
duration = utils.durationToSeconds(duration);
} else if (!isNaN(duration) && parseInt(duration) == duration) {
duration = parseInt(duration, 10);
} else {
duration = 0;
}
// Set the new option
options.video.duration = duration;
return this;
}
/**
* Sets the new aspetc ratio
*/
this.setVideoAspectRatio = function (aspect) {
// Check if aspect is a string
if (isNaN(aspect)) {
// Check if aspet is string xx:xx
if (/([0-9]+):([0-9]+)/.exec(aspect)) {
var check = /([0-9]+):([0-9]+)/.exec(aspect);
aspect = parseFloat((check[1] / check[2]));
} else {
aspect = this.metadata.video.aspect.value;
}
}
if (options.video == undefined)
options.video = new Object();
// Set the new option
options.video.aspect = aspect;
return this;
}
/**
* Set the size of the video
*/
this.setVideoSize = function (size, keepPixelAspectRatio, keepAspectRatio, paddingColor) {
if (options.video == undefined)
options.video = new Object();
// Set the new option
options.video.size = size;
options.video.keepPixelAspectRatio = keepPixelAspectRatio;
options.video.keepAspectRatio = keepAspectRatio;
options.video.paddingColor = paddingColor;
return this;
}
/**
* Sets the new audio codec
*/
this.setAudioCodec = function (codec) {
// Check if the codec is supported by ffmpeg version
if (this.info_configuration.encode.indexOf(codec) != -1) {
// Check if codec is equal 'MP3' and check if the version of ffmpeg support the libmp3lame function
if (codec == 'mp3' && this.info_configuration.modules.indexOf('libmp3lame') != -1)
codec = 'libmp3lame';
if (options.audio == undefined)
options.audio = new Object();
// Set the new option
options.audio.codec = codec;
return this;
} else
throw errors.renderError('codec_not_supported', codec);
}
/**
* Sets the audio sample frequency for audio outputs
*/
this.setAudioFrequency = function (frequency) {
if (options.audio == undefined)
options.audio = new Object();
// Set the new option
options.audio.frequency = frequency;
return this;
}
/**
* Sets the number of audio channels
*/
this.setAudioChannels = function (channel) {
// Check if the channel value is valid
if (presets.audio_channel.stereo == channel || presets.audio_channel.mono == channel) {
if (options.audio == undefined)
options.audio = new Object();
// Set the new option
options.audio.channel = channel;
return this;
} else
throw errors.renderError('audio_channel_is_invalid', channel);
}
/**
* Sets the audio bitrate
*/
this.setAudioBitRate = function (bitrate) {
if (options.audio == undefined)
options.audio = new Object();
// Set the new option
options.audio.bitrate = bitrate;
return this;
}
/**
* Sets the audio quality
*/
this.setAudioQuality = function (quality) {
if (options.audio == undefined)
options.audio = new Object();
// Set the new option
options.audio.quality = quality;
return this;
}
/**
* Sets the watermark
*/
this.setWatermark = function (watermarkPath, settings) {
// Base settings
var baseSettings = {
position : "SW" // Position: NE NC NW SE SC SW C CE CW
, margin_nord : null // Margin nord
, margin_sud : null // Margin sud
, margin_east : null // Margin east
, margin_west : null // Margin west
};
// Check if watermark exists
if (!fs.existsSync(watermarkPath))
throw errors.renderError('invalid_watermark', watermarkPath);
// Check if the settings are specified
if (settings != null)
utils.mergeObject(baseSettings, settings);
// Check if position is valid
if (baseSettings.position == null || utils.in_array(baseSettings.position, ['NE','NC','NW','SE','SC','SW','C','CE','CW']) === false)
throw errors.renderError('invalid_watermark_position', baseSettings.position);
// Check if margins are valid
if (baseSettings.margin_nord == null || isNaN(baseSettings.margin_nord))
baseSettings.margin_nord = 0;
if (baseSettings.margin_sud == null || isNaN(baseSettings.margin_sud))
baseSettings.margin_sud = 0;
if (baseSettings.margin_east == null || isNaN(baseSettings.margin_east))
baseSettings.margin_east = 0;
if (baseSettings.margin_west == null || isNaN(baseSettings.margin_west))
baseSettings.margin_west = 0;
var overlay = '';
var getSing = function (val, inverse) {
return (val > 0 ? (inverse ? '-' : '+') : (inverse ? '+' : '-')).toString() + Math.abs(val).toString();
}
var getHorizontalMargins = function (east, west) {
return getSing(east, false).toString() + getSing(west, true).toString();
}
var getVerticalMargins = function (nord, sud) {
return getSing(nord, false).toString() + getSing(sud, true).toString();
}
// Calculate formula
switch (baseSettings.position) {
case 'NE':
overlay = '0' + getHorizontalMargins(baseSettings.margin_east, baseSettings.margin_west) + ':0' + getVerticalMargins(baseSettings.margin_nord, baseSettings.margin_sud);
break;
case 'NC':
overlay = 'main_w/2-overlay_w/2' + getHorizontalMargins(baseSettings.margin_east, baseSettings.margin_west) + ':0' + getVerticalMargins(baseSettings.margin_nord, baseSettings.margin_sud);
break;
case 'NW':
overlay = 'main_w-overlay_w' + getHorizontalMargins(baseSettings.margin_east, baseSettings.margin_west) + ':0' + getVerticalMargins(baseSettings.margin_nord, baseSettings.margin_sud);
break;
case 'SE':
overlay = '0' + getHorizontalMargins(baseSettings.margin_east, baseSettings.margin_west) + ':main_h-overlay_h' + getVerticalMargins(baseSettings.margin_nord, baseSettings.margin_sud);
break;
case 'SC':
overlay = 'main_w/2-overlay_w/2' + getHorizontalMargins(baseSettings.margin_east, baseSettings.margin_west) + ':main_h-overlay_h' + getVerticalMargins(baseSettings.margin_nord, baseSettings.margin_sud);
break;
case 'SW':
overlay = 'main_w-overlay_w' + getHorizontalMargins(baseSettings.margin_east, baseSettings.margin_west) + ':main_h-overlay_h' + getVerticalMargins(baseSettings.margin_nord, baseSettings.margin_sud);
break;
case 'CE':
overlay = '0' + getHorizontalMargins(baseSettings.margin_east, baseSettings.margin_west) + ':main_h/2-overlay_h/2' + getVerticalMargins(baseSettings.margin_nord, baseSettings.margin_sud);
break;
case 'C':
overlay = 'main_w/2-overlay_w/2' + getHorizontalMargins(baseSettings.margin_east, baseSettings.margin_west) + ':main_h/2-overlay_h/2' + getVerticalMargins(baseSettings.margin_nord, baseSettings.margin_sud);
break;
case 'CW':
overlay = 'main_w-overlay_w' + getHorizontalMargins(baseSettings.margin_east, baseSettings.margin_west) + ':main_h/2-overlay_h/2' + getVerticalMargins(baseSettings.margin_nord, baseSettings.margin_sud);
break;
}
// Check if the call comes from internal function
if (arguments[2] == undefined || arguments[2] == null) {
if (options.video == undefined)
options.video = new Object();
// Set the new option
options.video.watermark = { path : watermarkPath, overlay : overlay };
return this;
} else if (arguments[2] != undefined && arguments[2] === true) {
this.addInput(watermarkPath);
this.addFilterComplex('overlay=' + overlay);
}
}
/**
* Save all set commands
*/
this.save = function (destionationFileName, callback) {
// Check if the 'video' is present in the options
if (options.hasOwnProperty('video')) {
// Check if video is disabled
if (options.video.hasOwnProperty('disabled')) {
this.addCommand('-vn');
} else {
// Check all video property
if (options.video.hasOwnProperty('format'))
this.addCommand('-f', options.video.format);
if (options.video.hasOwnProperty('codec'))
this.addCommand('-vcodec', options.video.codec);
if (options.video.hasOwnProperty('bitrate'))
this.addCommand('-b', parseInt(options.video.bitrate, 10) + 'kb');
if (options.video.hasOwnProperty('framerate'))
this.addCommand('-r', parseInt(options.video.framerate, 10));
if (options.video.hasOwnProperty('startTime'))
this.addCommand('-ss', parseInt(options.video.startTime, 10));
if (options.video.hasOwnProperty('duration'))
this.addCommand('-t', parseInt(options.video.duration, 10));
if (options.video.hasOwnProperty('watermark')) {
this.addInput(options.video.watermark.path);
this.addFilterComplex('overlay=' + options.video.watermark.overlay);
}
// Check if the video should be scaled
if (options.video.hasOwnProperty('size')) {
var newDimension = _calculateNewDimension.call(this);
if (newDimension.aspect != null) {
this.addFilterComplex('scale=iw*sar:ih, pad=max(iw\\,ih*(' + newDimension.aspect.x + '/' + newDimension.aspect.y + ')):ow/(' + newDimension.aspect.x + '/' + newDimension.aspect.y + '):(ow-iw)/2:(oh-ih)/2' + (options.video.paddingColor != null ? ':' + options.video.paddingColor : ''));
this.addCommand('-aspect', newDimension.aspect.string);
}
this.addCommand('-s', newDimension.width + 'x' + newDimension.height);
}
}
}
// Check if the 'audio' is present in the options
if (options.hasOwnProperty('audio')) {
// Check if audio is disabled
if (options.audio.hasOwnProperty('disabled')) {
this.addCommand('-an');
} else {
// Check all audio property
if (options.audio.hasOwnProperty('codec'))
this.addCommand('-acodec', options.audio.codec);
if (options.audio.hasOwnProperty('frequency'))
this.addCommand('-ar', parseInt(options.audio.frequency));
if (options.audio.hasOwnProperty('channel'))
this.addCommand('-ac', options.audio.channel);
if (options.audio.hasOwnProperty('quality'))
this.addCommand('-aq', options.audio.quality);
if (options.audio.hasOwnProperty('bitrate'))
this.addCommand('-ab', parseInt(options.audio.bitrate, 10) + 'k');
}
}
setOutput(destionationFileName);
return execCommand.call(this, callback);
}
/*********************/
/* INTERNAL FUNCTION */
/*********************/
/**
* Reset the list of commands
*/
var resetCommands = function (self) {
commands = new Array()
inputs = [self.file_path];
filtersComlpex = new Array();
output = null;
options = new Object();
}
/**
* Calculate width, height and aspect ratio by the new dimension data
*/
var _calculateNewDimension = function () {
// Check if keepPixelAspectRatio is undefined
var keepPixelAspectRatio = typeof options.video.keepPixelAspectRatio != 'boolean' ? false : options.video.keepPixelAspectRatio;
// Check if keepAspectRatio is undefined
var keepAspectRatio = typeof options.video.keepAspectRatio != 'boolean' ? false : options.video.keepAspectRatio;
// Resolution to be taken as a reference
var referrerResolution = this.metadata.video.resolution;
// Check if is need keep pixel aspect ratio
if (keepPixelAspectRatio) {
// Check if exists resolution for pixel aspect ratio
if (utils.isEmptyObj(this.metadata.video.resolutionSquare))
throw errors.renderError('resolution_square_not_defined');
// Apply the resolutionSquare
referrerResolution = this.metadata.video.resolutionSquare;
}
// Final data
var width = null
, height = null
, aspect = null;
// Regex to check which type of dimension was specified
var fixedWidth = /([0-9]+)x\?/.exec(options.video.size)
, fixedHeight = /\?x([0-9]+)/.exec(options.video.size)
, percentage = /([0-9]{1,2})%/.exec(options.video.size)
, classicSize = /([0-9]+)x([0-9]+)/.exec(options.video.size);
if (fixedWidth) {
// Set the width dimension
width = parseInt(fixedWidth[1], 10);
// Check if the video has the aspect ratio setted
if (!utils.isEmptyObj(this.metadata.video.aspect)) {
height = Math.round((width / this.metadata.video.aspect.x) * this.metadata.video.aspect.y);
} else {
// Calculte the new height
height = Math.round(referrerResolution.h / (referrerResolution.w / parseInt(fixedWidth[1], 10)));
}
} else if (fixedHeight) {
// Set the width dimension
height = parseInt(fixedHeight[1], 10);
// Check if the video has the aspect ratio setted
if (!utils.isEmptyObj(this.metadata.video.aspect)) {
width = Math.round((height / this.metadata.video.aspect.y) * this.metadata.video.aspect.x);
} else {
// Calculte the new width
width = Math.round(referrerResolution.w / (referrerResolution.h / parseInt(fixedHeight[1], 10)));
}
} else if (percentage) {
// Calculte the ratio from percentage
var ratio = parseInt(percentage[1], 10) / 100;
// Calculate the new dimensions
width = Math.round(referrerResolution.w * ratio);
height = Math.round(referrerResolution.h * ratio);
} else if (classicSize) {
width = parseInt(classicSize[1], 10);
height = parseInt(classicSize[2], 10);
} else
throw errors.renderError('size_format', options.video.size);
// If the width or height are not multiples of 2 will be decremented by one unit
if (width % 2 != 0) width -= 1;
if (height % 2 != 0) height -= 1;
if (keepAspectRatio) {
// Calculate the new aspect ratio
var gcdValue = utils.gcd(width, height);
aspect = new Object();
aspect.x = width / gcdValue;
aspect.y = height / gcdValue;
aspect.string = aspect.x + ':' + aspect.y;
}
return { width : width, height : height, aspect : aspect };
}
/**
* Executing the commands list
*/
var execCommand = function (callback, folder) {
// Checking if folder is defined
var onlyDestinationFile = folder != undefined ? false : true;
// Building the value for return value. Check if the callback is not a function. In this case will created a new instance of the deferred class
var deferred = typeof callback != 'function' ? when.defer() : { promise : null };
// Create a copy of the commands list
var finalCommands = ['ffmpeg -i']
.concat(inputs.join(' -i '))
.concat(commands.join(' '))
.concat(filtersComlpex.length > 0 ? ['-filter_complex "'].concat(filtersComlpex.join(', ')).join('') + '"' : [])
.concat([output]);
// Reset commands
resetCommands(this);
// Execute the commands from the list
utils.exec(finalCommands, settings, function (error, stdout, stderr) {
// Building the result
var result = null;
if (!error) {
// Check if show only destination filename or the complete file list
if (onlyDestinationFile) {
result = finalCommands[finalCommands.length-1];
} else {
// Clean possible "/" at the end of the string
if (folder.charAt(folder.length-1) == "/")
folder = folder.substr(0, folder.length-1);
// Read file list inside the folder
result = fs.readdirSync(folder);
// Scan all file and prepend the folder path
for (var i in result)
result[i] = [folder, result[i]].join('/')
}
}
// Check if the callback is a function
if (typeof callback == 'function') {
// Call the callback to return the info
callback(error, result);
} else {
if (error) {
// Negative response
deferred.reject(error);
} else {
// Positive response
deferred.resolve(result);
}
}
});
// Return a possible promise instance
return deferred.promise;
}
/*******************/
/* PRESET FUNCTION */
/*******************/
/**
* Extracting sound from a video, and save it as Mp3
*/
this.fnExtractSoundToMP3 = function (destionationFileName, callback) {
// Check if file already exists. In this case will remove it
if (fs.existsSync(destionationFileName))
fs.unlinkSync(destionationFileName);
// Building the final path
var destinationDirName = path.dirname(destionationFileName)
, destinationFileNameWE = path.basename(destionationFileName, path.extname(destionationFileName)) + '.mp3'
, finalPath = path.join(destinationDirName, destinationFileNameWE);
resetCommands(this);
// Adding commands to the list
this.addCommand('-vn');
this.addCommand('-ar', 44100);
this.addCommand('-ac', 2);
this.addCommand('-ab', 192);
this.addCommand('-f', 'mp3');
// Add destination file path to the command list
setOutput(finalPath);
// Executing the commands list
return execCommand.call(this, callback);
}
/**
* Extract frame from video file
*/
this.fnExtractFrameToJPG = function (/* destinationFolder, settings, callback */) {
var destinationFolder = null
, newSettings = null
, callback = null;
var settings = {
start_time : null // Start time to recording
, duration_time : null // Duration of recording
, frame_rate : null // Number of the frames to capture in one second
, size : null // Dimension each frame
, number : null // Total frame to capture
, every_n_frames : null // Frame to capture every N frames
, every_n_seconds : null // Frame to capture every N seconds
, every_n_percentage : null // Frame to capture every N percentage range
, keep_pixel_aspect_ratio : true // Mantain the original pixel video aspect ratio
, keep_aspect_ratio : true // Mantain the original aspect ratio
, padding_color : 'black' // Padding color
, file_name : null // File name
};
// Scan all arguments
for (var i in arguments) {
// Check the type of the argument
switch (typeof arguments[i]) {
case 'string':
destinationFolder = arguments[i];
break;
case 'object':
newSettings = arguments[i];
break;
case 'function':
callback = arguments[i];
break;
}
}
// Check if the settings are specified
if (newSettings !== null)
utils.mergeObject(settings, newSettings);
// Check if 'start_time' is in the format hours:minutes:seconds
if (settings.start_time != null) {
if (/([0-9]+):([0-9]{2}):([0-9]{2})/.exec(settings.start_time))
settings.start_time = utils.durationToSeconds(settings.start_time);
else if (!isNaN(settings.start_time))
settings.start_time = parseInt(settings.start_time, 10);
else
settings.start_time = null;
}
// Check if 'duration_time' is in the format hours:minutes:seconds
if (settings.duration_time != null) {
if (/([0-9]+):([0-9]{2}):([0-9]{2})/.exec(settings.duration_time))
settings.duration_time = utils.durationToSeconds(settings.duration_time);
else if (!isNaN(settings.duration_time))
settings.duration_time = parseInt(settings.duration_time, 10);
else
settings.duration_time = null;
}
// Check if the value of the framerate is number type
if (settings.frame_rate != null && isNaN(settings.frame_rate))
settings.frame_rate = null;
// If the size is not settings then the size of the screenshots is equal to video size
if (settings.size == null)
settings.size = this.metadata.video.resolution.w + 'x' + this.metadata.video.resolution.h;
// Check if the value of the 'number frame to capture' is number type
if (settings.number != null && isNaN(settings.number))
settings.number = null;
var every_n_check = 0;
// Check if the value of the 'every_n_frames' is number type
if (settings.every_n_frames != null && isNaN(settings.every_n_frames)) {
settings.every_n_frames = null;
every_n_check++;
}
// Check if the value of the 'every_n_seconds' is number type
if (settings.every_n_seconds != null && isNaN(settings.every_n_seconds)) {
settings.every_n_seconds = null;
every_n_check++;
}
// Check if the value of the 'every_n_percentage' is number type
if (settings.every_n_percentage != null && (isNaN(settings.every_n_percentage) || settings.every_n_percentage > 100)) {
settings.every_n_percentage = null;
every_n_check++;
}
if (every_n_check >= 2) {
if (callback) {
callback(errors.renderError('extract_frame_invalid_everyN_options'));
} else {
throw errors.renderError('extract_frame_invalid_everyN_options');
}
}
// If filename is null then his value is equal to original filename
if (settings.file_name == null) {
settings.file_name = path.basename(this.file_path, path.extname(this.file_path));
} else {
// Retrieve all possible replacements
var replacements = settings.file_name.match(/(\%[a-zA-Z]{1})/g);
// Check if exists replacements. The scan all replacements and build the final filename
if (replacements) {
for (var i in replacements) {
switch (replacements[i]) {
case '%t':
settings.file_name = settings.file_name.replace('%t', new Date().getTime());
break;
case '%s':
settings.file_name = settings.file_name.replace('%s', settings.size);
break;
case '%x':
settings.file_name = settings.file_name.replace('%x', settings.size.split(':')[0]);
break;
case '%y':
settings.file_name = settings.file_name.replace('%y', settings.size.split(':')[1]);
break;
default:
settings.file_name = settings.file_name.replace(replacements[i], '');
break;
}
}
}
}
// At the filename will added the number of the frame
settings.file_name = path.basename(settings.file_name, path.extname(settings.file_name)) + '_%d.jpg';
// Create the directory to save the extracted frames
utils.mkdir(destinationFolder, 0777);
resetCommands(this);
// Adding commands to the list
if (settings.startTime)
this.addCommand('-ss', settings.startTime);
if (settings.duration_time)
this.addCommand('-t', settings.duration_time);
if (settings.frame_rate)
this.addCommand('-r', settings.frame_rate);
// Setting the size and padding settings
this.setVideoSize(settings.size, settings.keep_pixel_aspect_ratio, settings.keep_aspect_ratio, settings.padding_color);
// Get the dimensions
var newDimension = _calculateNewDimension.call(this);
// Apply the size and padding commands
this.addCommand('-s', newDimension.width + 'x' + newDimension.height);
// CHeck if isset aspect ratio options
if (newDimension.aspect != null) {
this.addFilterComplex('scale=iw*sar:ih, pad=max(iw\\,ih*(' + newDimension.aspect.x + '/' + newDimension.aspect.y + ')):ow/(' + newDimension.aspect.x + '/' + newDimension.aspect.y + '):(ow-iw)/2:(oh-ih)/2' + (settings.padding_color != null ? ':' + settings.padding_color : ''));
this.addCommand('-aspect', newDimension.aspect.string);
}
if (settings.number)
this.addCommand('-vframes', settings.number);
if (settings.every_n_frames) {
this.addCommand('-vsync', 0);
this.addFilterComplex('select=not(mod(n\\,' + settings.every_n_frames + '))');
}
if (settings.every_n_seconds) {
this.addCommand('-vsync', 0);
this.addFilterComplex('select=not(mod(t\\,' + settings.every_n_seconds + '))');
}
if (settings.every_n_percentage) {
this.addCommand('-vsync', 0);
this.addFilterComplex('select=not(mod(t\\,' + parseInt((this.metadata.duration.seconds / 100) * settings.every_n_percentage) + '))');
}
// Add destination file path to the command list
setOutput([destinationFolder,settings.file_name].join('/'));
// Executing the commands list
return execCommand.call(this, callback, destinationFolder);
}
/**
* Add a watermark to the video and save it
*/
this.fnAddWatermark = function (watermarkPath /* newFilepath , settings, callback */) {
var newFilepath = null
, newSettings = null
, callback = null;
// Scan all arguments
for (var i = 1; i < arguments.length; i++) {
// Check the type of the argument
switch (typeof arguments[i]) {
case 'string':
newFilepath = arguments[i];
break;
case 'object':
newSettings = arguments[i];
break;
case 'function':
callback = arguments[i];
break;
}
}
resetCommands(this);
// Call the function to add the watermark options
this.setWatermark(watermarkPath, newSettings, true);
if (newFilepath == null)
newFilepath = path.dirname(this.file_path) + '/' +
path.basename(this.file_path, path.extname(this.file_path)) + '_watermark_' +
path.basename(watermarkPath, path.extname(watermarkPath)) +
path.extname(this.file_path);
// Add destination file path to the command list
setOutput(newFilepath);
// Executing the commands list
return execCommand.call(this, callback);
}
/**
* Constructor
*/
var __constructor = function (self) {
resetCommands(self);
}(this);
}