123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- 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);
- }
|