| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="utf-8"> |
| | <title>JSDoc: Source: capabilities.js</title> |
| |
|
| | <script src="scripts/prettify/prettify.js"> </script> |
| | <script src="scripts/prettify/lang-css.js"> </script> |
| | |
| | |
| | |
| | <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> |
| | <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> |
| | </head> |
| |
|
| | <body> |
| |
|
| | <div id="main"> |
| |
|
| | <h1 class="page-title">Source: capabilities.js</h1> |
| |
|
| | |
| |
|
| |
|
| | |
| | <section> |
| | <article> |
| | <pre class="prettyprint source linenums"><code>/*jshint node:true*/ |
| | 'use strict'; |
| |
|
| | var fs = require('fs'); |
| | var path = require('path'); |
| | var async = require('async'); |
| | var utils = require('./utils'); |
| |
|
| | /* |
| | *! Capability helpers |
| | */ |
| |
|
| | var avCodecRegexp = /^\s*([D ])([E ])([VAS])([S ])([D ])([T ]) ([^ ]+) +(.*)$/; |
| | var ffCodecRegexp = /^\s*([D\.])([E\.])([VAS])([I\.])([L\.])([S\.]) ([^ ]+) +(.*)$/; |
| | var ffEncodersRegexp = /\(encoders:([^\)]+)\)/; |
| | var ffDecodersRegexp = /\(decoders:([^\)]+)\)/; |
| | var encodersRegexp = /^\s*([VAS\.])([F\.])([S\.])([X\.])([B\.])([D\.]) ([^ ]+) +(.*)$/; |
| | var formatRegexp = /^\s*([D ])([E ])\s+([^ ]+)\s+(.*)$/; |
| | var lineBreakRegexp = /\r\n|\r|\n/; |
| | var filterRegexp = /^(?: [T\.][S\.][C\.] )?([^ ]+) +(AA?|VV?|\|)->(AA?|VV?|\|) +(.*)$/; |
| |
|
| | var cache = {}; |
| |
|
| | module.exports = function(proto) { |
| | /** |
| | * Manually define the ffmpeg binary full path. |
| | * |
| | * @method FfmpegCommand#setFfmpegPath |
| | * |
| | * @param {String} ffmpegPath The full path to the ffmpeg binary. |
| | * @return FfmpegCommand |
| | */ |
| | proto.setFfmpegPath = function(ffmpegPath) { |
| | cache.ffmpegPath = ffmpegPath; |
| | return this; |
| | }; |
| |
|
| | /** |
| | * Manually define the ffprobe binary full path. |
| | * |
| | * @method FfmpegCommand#setFfprobePath |
| | * |
| | * @param {String} ffprobePath The full path to the ffprobe binary. |
| | * @return FfmpegCommand |
| | */ |
| | proto.setFfprobePath = function(ffprobePath) { |
| | cache.ffprobePath = ffprobePath; |
| | return this; |
| | }; |
| |
|
| | /** |
| | * Manually define the flvtool2/flvmeta binary full path. |
| | * |
| | * @method FfmpegCommand#setFlvtoolPath |
| | * |
| | * @param {String} flvtool The full path to the flvtool2 or flvmeta binary. |
| | * @return FfmpegCommand |
| | */ |
| | proto.setFlvtoolPath = function(flvtool) { |
| | cache.flvtoolPath = flvtool; |
| | return this; |
| | }; |
| |
|
| | /** |
| | * Forget executable paths |
| | * |
| | * (only used for testing purposes) |
| | * |
| | * @method FfmpegCommand#_forgetPaths |
| | * @private |
| | */ |
| | proto._forgetPaths = function() { |
| | delete cache.ffmpegPath; |
| | delete cache.ffprobePath; |
| | delete cache.flvtoolPath; |
| | }; |
| |
|
| | /** |
| | * Check for ffmpeg availability |
| | * |
| | * If the FFMPEG_PATH environment variable is set, try to use it. |
| | * If it is unset or incorrect, try to find ffmpeg in the PATH instead. |
| | * |
| | * @method FfmpegCommand#_getFfmpegPath |
| | * @param {Function} callback callback with signature (err, path) |
| | * @private |
| | */ |
| | proto._getFfmpegPath = function(callback) { |
| | if ('ffmpegPath' in cache) { |
| | return callback(null, cache.ffmpegPath); |
| | } |
| |
|
| | async.waterfall([ |
| | // Try FFMPEG_PATH |
| | function(cb) { |
| | if (process.env.FFMPEG_PATH) { |
| | fs.exists(process.env.FFMPEG_PATH, function(exists) { |
| | if (exists) { |
| | cb(null, process.env.FFMPEG_PATH); |
| | } else { |
| | cb(null, ''); |
| | } |
| | }); |
| | } else { |
| | cb(null, ''); |
| | } |
| | }, |
| |
|
| | // Search in the PATH |
| | function(ffmpeg, cb) { |
| | if (ffmpeg.length) { |
| | return cb(null, ffmpeg); |
| | } |
| |
|
| | utils.which('ffmpeg', function(err, ffmpeg) { |
| | cb(err, ffmpeg); |
| | }); |
| | } |
| | ], function(err, ffmpeg) { |
| | if (err) { |
| | callback(err); |
| | } else { |
| | callback(null, cache.ffmpegPath = (ffmpeg || '')); |
| | } |
| | }); |
| | }; |
| |
|
| |
|
| | /** |
| | * Check for ffprobe availability |
| | * |
| | * If the FFPROBE_PATH environment variable is set, try to use it. |
| | * If it is unset or incorrect, try to find ffprobe in the PATH instead. |
| | * If this still fails, try to find ffprobe in the same directory as ffmpeg. |
| | * |
| | * @method FfmpegCommand#_getFfprobePath |
| | * @param {Function} callback callback with signature (err, path) |
| | * @private |
| | */ |
| | proto._getFfprobePath = function(callback) { |
| | var self = this; |
| |
|
| | if ('ffprobePath' in cache) { |
| | return callback(null, cache.ffprobePath); |
| | } |
| |
|
| | async.waterfall([ |
| | // Try FFPROBE_PATH |
| | function(cb) { |
| | if (process.env.FFPROBE_PATH) { |
| | fs.exists(process.env.FFPROBE_PATH, function(exists) { |
| | cb(null, exists ? process.env.FFPROBE_PATH : ''); |
| | }); |
| | } else { |
| | cb(null, ''); |
| | } |
| | }, |
| |
|
| | // Search in the PATH |
| | function(ffprobe, cb) { |
| | if (ffprobe.length) { |
| | return cb(null, ffprobe); |
| | } |
| |
|
| | utils.which('ffprobe', function(err, ffprobe) { |
| | cb(err, ffprobe); |
| | }); |
| | }, |
| |
|
| | // Search in the same directory as ffmpeg |
| | function(ffprobe, cb) { |
| | if (ffprobe.length) { |
| | return cb(null, ffprobe); |
| | } |
| |
|
| | self._getFfmpegPath(function(err, ffmpeg) { |
| | if (err) { |
| | cb(err); |
| | } else if (ffmpeg.length) { |
| | var name = utils.isWindows ? 'ffprobe.exe' : 'ffprobe'; |
| | var ffprobe = path.join(path.dirname(ffmpeg), name); |
| | fs.exists(ffprobe, function(exists) { |
| | cb(null, exists ? ffprobe : ''); |
| | }); |
| | } else { |
| | cb(null, ''); |
| | } |
| | }); |
| | } |
| | ], function(err, ffprobe) { |
| | if (err) { |
| | callback(err); |
| | } else { |
| | callback(null, cache.ffprobePath = (ffprobe || '')); |
| | } |
| | }); |
| | }; |
| |
|
| |
|
| | /** |
| | * Check for flvtool2/flvmeta availability |
| | * |
| | * If the FLVTOOL2_PATH or FLVMETA_PATH environment variable are set, try to use them. |
| | * If both are either unset or incorrect, try to find flvtool2 or flvmeta in the PATH instead. |
| | * |
| | * @method FfmpegCommand#_getFlvtoolPath |
| | * @param {Function} callback callback with signature (err, path) |
| | * @private |
| | */ |
| | proto._getFlvtoolPath = function(callback) { |
| | if ('flvtoolPath' in cache) { |
| | return callback(null, cache.flvtoolPath); |
| | } |
| |
|
| | async.waterfall([ |
| | // Try FLVMETA_PATH |
| | function(cb) { |
| | if (process.env.FLVMETA_PATH) { |
| | fs.exists(process.env.FLVMETA_PATH, function(exists) { |
| | cb(null, exists ? process.env.FLVMETA_PATH : ''); |
| | }); |
| | } else { |
| | cb(null, ''); |
| | } |
| | }, |
| |
|
| | // Try FLVTOOL2_PATH |
| | function(flvtool, cb) { |
| | if (flvtool.length) { |
| | return cb(null, flvtool); |
| | } |
| |
|
| | if (process.env.FLVTOOL2_PATH) { |
| | fs.exists(process.env.FLVTOOL2_PATH, function(exists) { |
| | cb(null, exists ? process.env.FLVTOOL2_PATH : ''); |
| | }); |
| | } else { |
| | cb(null, ''); |
| | } |
| | }, |
| |
|
| | // Search for flvmeta in the PATH |
| | function(flvtool, cb) { |
| | if (flvtool.length) { |
| | return cb(null, flvtool); |
| | } |
| |
|
| | utils.which('flvmeta', function(err, flvmeta) { |
| | cb(err, flvmeta); |
| | }); |
| | }, |
| |
|
| | // Search for flvtool2 in the PATH |
| | function(flvtool, cb) { |
| | if (flvtool.length) { |
| | return cb(null, flvtool); |
| | } |
| |
|
| | utils.which('flvtool2', function(err, flvtool2) { |
| | cb(err, flvtool2); |
| | }); |
| | }, |
| | ], function(err, flvtool) { |
| | if (err) { |
| | callback(err); |
| | } else { |
| | callback(null, cache.flvtoolPath = (flvtool || '')); |
| | } |
| | }); |
| | }; |
| |
|
| |
|
| | /** |
| | * A callback passed to {@link FfmpegCommand#availableFilters}. |
| | * |
| | * @callback FfmpegCommand~filterCallback |
| | * @param {Error|null} err error object or null if no error happened |
| | * @param {Object} filters filter object with filter names as keys and the following |
| | * properties for each filter: |
| | * @param {String} filters.description filter description |
| | * @param {String} filters.input input type, one of 'audio', 'video' and 'none' |
| | * @param {Boolean} filters.multipleInputs whether the filter supports multiple inputs |
| | * @param {String} filters.output output type, one of 'audio', 'video' and 'none' |
| | * @param {Boolean} filters.multipleOutputs whether the filter supports multiple outputs |
| | */ |
| |
|
| | /** |
| | * Query ffmpeg for available filters |
| | * |
| | * @method FfmpegCommand#availableFilters |
| | * @category Capabilities |
| | * @aliases getAvailableFilters |
| | * |
| | * @param {FfmpegCommand~filterCallback} callback callback function |
| | */ |
| | proto.availableFilters = |
| | proto.getAvailableFilters = function(callback) { |
| | if ('filters' in cache) { |
| | return callback(null, cache.filters); |
| | } |
| |
|
| | this._spawnFfmpeg(['-filters'], { captureStdout: true, stdoutLines: 0 }, function (err, stdoutRing) { |
| | if (err) { |
| | return callback(err); |
| | } |
| |
|
| | var stdout = stdoutRing.get(); |
| | var lines = stdout.split('\n'); |
| | var data = {}; |
| | var types = { A: 'audio', V: 'video', '|': 'none' }; |
| |
|
| | lines.forEach(function(line) { |
| | var match = line.match(filterRegexp); |
| | if (match) { |
| | data[match[1]] = { |
| | description: match[4], |
| | input: types[match[2].charAt(0)], |
| | multipleInputs: match[2].length > 1, |
| | output: types[match[3].charAt(0)], |
| | multipleOutputs: match[3].length > 1 |
| | }; |
| | } |
| | }); |
| |
|
| | callback(null, cache.filters = data); |
| | }); |
| | }; |
| |
|
| |
|
| | /** |
| | * A callback passed to {@link FfmpegCommand#availableCodecs}. |
| | * |
| | * @callback FfmpegCommand~codecCallback |
| | * @param {Error|null} err error object or null if no error happened |
| | * @param {Object} codecs codec object with codec names as keys and the following |
| | * properties for each codec (more properties may be available depending on the |
| | * ffmpeg version used): |
| | * @param {String} codecs.description codec description |
| | * @param {Boolean} codecs.canDecode whether the codec is able to decode streams |
| | * @param {Boolean} codecs.canEncode whether the codec is able to encode streams |
| | */ |
| |
|
| | /** |
| | * Query ffmpeg for available codecs |
| | * |
| | * @method FfmpegCommand#availableCodecs |
| | * @category Capabilities |
| | * @aliases getAvailableCodecs |
| | * |
| | * @param {FfmpegCommand~codecCallback} callback callback function |
| | */ |
| | proto.availableCodecs = |
| | proto.getAvailableCodecs = function(callback) { |
| | if ('codecs' in cache) { |
| | return callback(null, cache.codecs); |
| | } |
| |
|
| | this._spawnFfmpeg(['-codecs'], { captureStdout: true, stdoutLines: 0 }, function(err, stdoutRing) { |
| | if (err) { |
| | return callback(err); |
| | } |
| |
|
| | var stdout = stdoutRing.get(); |
| | var lines = stdout.split(lineBreakRegexp); |
| | var data = {}; |
| |
|
| | lines.forEach(function(line) { |
| | var match = line.match(avCodecRegexp); |
| | if (match && match[7] !== '=') { |
| | data[match[7]] = { |
| | type: { 'V': 'video', 'A': 'audio', 'S': 'subtitle' }[match[3]], |
| | description: match[8], |
| | canDecode: match[1] === 'D', |
| | canEncode: match[2] === 'E', |
| | drawHorizBand: match[4] === 'S', |
| | directRendering: match[5] === 'D', |
| | weirdFrameTruncation: match[6] === 'T' |
| | }; |
| | } |
| |
|
| | match = line.match(ffCodecRegexp); |
| | if (match && match[7] !== '=') { |
| | var codecData = data[match[7]] = { |
| | type: { 'V': 'video', 'A': 'audio', 'S': 'subtitle' }[match[3]], |
| | description: match[8], |
| | canDecode: match[1] === 'D', |
| | canEncode: match[2] === 'E', |
| | intraFrameOnly: match[4] === 'I', |
| | isLossy: match[5] === 'L', |
| | isLossless: match[6] === 'S' |
| | }; |
| |
|
| | var encoders = codecData.description.match(ffEncodersRegexp); |
| | encoders = encoders ? encoders[1].trim().split(' ') : []; |
| |
|
| | var decoders = codecData.description.match(ffDecodersRegexp); |
| | decoders = decoders ? decoders[1].trim().split(' ') : []; |
| |
|
| | if (encoders.length || decoders.length) { |
| | var coderData = {}; |
| | utils.copy(codecData, coderData); |
| | delete coderData.canEncode; |
| | delete coderData.canDecode; |
| |
|
| | encoders.forEach(function(name) { |
| | data[name] = {}; |
| | utils.copy(coderData, data[name]); |
| | data[name].canEncode = true; |
| | }); |
| |
|
| | decoders.forEach(function(name) { |
| | if (name in data) { |
| | data[name].canDecode = true; |
| | } else { |
| | data[name] = {}; |
| | utils.copy(coderData, data[name]); |
| | data[name].canDecode = true; |
| | } |
| | }); |
| | } |
| | } |
| | }); |
| |
|
| | callback(null, cache.codecs = data); |
| | }); |
| | }; |
| |
|
| |
|
| | /** |
| | * A callback passed to {@link FfmpegCommand#availableEncoders}. |
| | * |
| | * @callback FfmpegCommand~encodersCallback |
| | * @param {Error|null} err error object or null if no error happened |
| | * @param {Object} encoders encoders object with encoder names as keys and the following |
| | * properties for each encoder: |
| | * @param {String} encoders.description codec description |
| | * @param {Boolean} encoders.type "audio", "video" or "subtitle" |
| | * @param {Boolean} encoders.frameMT whether the encoder is able to do frame-level multithreading |
| | * @param {Boolean} encoders.sliceMT whether the encoder is able to do slice-level multithreading |
| | * @param {Boolean} encoders.experimental whether the encoder is experimental |
| | * @param {Boolean} encoders.drawHorizBand whether the encoder supports draw_horiz_band |
| | * @param {Boolean} encoders.directRendering whether the encoder supports direct encoding method 1 |
| | */ |
| |
|
| | /** |
| | * Query ffmpeg for available encoders |
| | * |
| | * @method FfmpegCommand#availableEncoders |
| | * @category Capabilities |
| | * @aliases getAvailableEncoders |
| | * |
| | * @param {FfmpegCommand~encodersCallback} callback callback function |
| | */ |
| | proto.availableEncoders = |
| | proto.getAvailableEncoders = function(callback) { |
| | if ('encoders' in cache) { |
| | return callback(null, cache.encoders); |
| | } |
| |
|
| | this._spawnFfmpeg(['-encoders'], { captureStdout: true, stdoutLines: 0 }, function(err, stdoutRing) { |
| | if (err) { |
| | return callback(err); |
| | } |
| |
|
| | var stdout = stdoutRing.get(); |
| | var lines = stdout.split(lineBreakRegexp); |
| | var data = {}; |
| |
|
| | lines.forEach(function(line) { |
| | var match = line.match(encodersRegexp); |
| | if (match && match[7] !== '=') { |
| | data[match[7]] = { |
| | type: { 'V': 'video', 'A': 'audio', 'S': 'subtitle' }[match[1]], |
| | description: match[8], |
| | frameMT: match[2] === 'F', |
| | sliceMT: match[3] === 'S', |
| | experimental: match[4] === 'X', |
| | drawHorizBand: match[5] === 'B', |
| | directRendering: match[6] === 'D' |
| | }; |
| | } |
| | }); |
| |
|
| | callback(null, cache.encoders = data); |
| | }); |
| | }; |
| |
|
| |
|
| | /** |
| | * A callback passed to {@link FfmpegCommand#availableFormats}. |
| | * |
| | * @callback FfmpegCommand~formatCallback |
| | * @param {Error|null} err error object or null if no error happened |
| | * @param {Object} formats format object with format names as keys and the following |
| | * properties for each format: |
| | * @param {String} formats.description format description |
| | * @param {Boolean} formats.canDemux whether the format is able to demux streams from an input file |
| | * @param {Boolean} formats.canMux whether the format is able to mux streams into an output file |
| | */ |
| |
|
| | /** |
| | * Query ffmpeg for available formats |
| | * |
| | * @method FfmpegCommand#availableFormats |
| | * @category Capabilities |
| | * @aliases getAvailableFormats |
| | * |
| | * @param {FfmpegCommand~formatCallback} callback callback function |
| | */ |
| | proto.availableFormats = |
| | proto.getAvailableFormats = function(callback) { |
| | if ('formats' in cache) { |
| | return callback(null, cache.formats); |
| | } |
| |
|
| | // Run ffmpeg -formats |
| | this._spawnFfmpeg(['-formats'], { captureStdout: true, stdoutLines: 0 }, function (err, stdoutRing) { |
| | if (err) { |
| | return callback(err); |
| | } |
| |
|
| | // Parse output |
| | var stdout = stdoutRing.get(); |
| | var lines = stdout.split(lineBreakRegexp); |
| | var data = {}; |
| |
|
| | lines.forEach(function(line) { |
| | var match = line.match(formatRegexp); |
| | if (match) { |
| | match[3].split(',').forEach(function(format) { |
| | if (!(format in data)) { |
| | data[format] = { |
| | description: match[4], |
| | canDemux: false, |
| | canMux: false |
| | }; |
| | } |
| |
|
| | if (match[1] === 'D') { |
| | data[format].canDemux = true; |
| | } |
| | if (match[2] === 'E') { |
| | data[format].canMux = true; |
| | } |
| | }); |
| | } |
| | }); |
| |
|
| | callback(null, cache.formats = data); |
| | }); |
| | }; |
| |
|
| |
|
| | /** |
| | * Check capabilities before executing a command |
| | * |
| | * Checks whether all used codecs and formats are indeed available |
| | * |
| | * @method FfmpegCommand#_checkCapabilities |
| | * @param {Function} callback callback with signature (err) |
| | * @private |
| | */ |
| | proto._checkCapabilities = function(callback) { |
| | var self = this; |
| | async.waterfall([ |
| | // Get available formats |
| | function(cb) { |
| | self.availableFormats(cb); |
| | }, |
| |
|
| | // Check whether specified formats are available |
| | function(formats, cb) { |
| | var unavailable; |
| |
|
| | // Output format(s) |
| | unavailable = self._outputs |
| | .reduce(function(fmts, output) { |
| | var format = output.options.find('-f', 1); |
| | if (format) { |
| | if (!(format[0] in formats) || !(formats[format[0]].canMux)) { |
| | fmts.push(format); |
| | } |
| | } |
| |
|
| | return fmts; |
| | }, []); |
| |
|
| | if (unavailable.length === 1) { |
| | return cb(new Error('Output format ' + unavailable[0] + ' is not available')); |
| | } else if (unavailable.length > 1) { |
| | return cb(new Error('Output formats ' + unavailable.join(', ') + ' are not available')); |
| | } |
| |
|
| | // Input format(s) |
| | unavailable = self._inputs |
| | .reduce(function(fmts, input) { |
| | var format = input.options.find('-f', 1); |
| | if (format) { |
| | if (!(format[0] in formats) || !(formats[format[0]].canDemux)) { |
| | fmts.push(format[0]); |
| | } |
| | } |
| |
|
| | return fmts; |
| | }, []); |
| |
|
| | if (unavailable.length === 1) { |
| | return cb(new Error('Input format ' + unavailable[0] + ' is not available')); |
| | } else if (unavailable.length > 1) { |
| | return cb(new Error('Input formats ' + unavailable.join(', ') + ' are not available')); |
| | } |
| |
|
| | cb(); |
| | }, |
| |
|
| | // Get available codecs |
| | function(cb) { |
| | self.availableEncoders(cb); |
| | }, |
| |
|
| | // Check whether specified codecs are available and add strict experimental options if needed |
| | function(encoders, cb) { |
| | var unavailable; |
| |
|
| | // Audio codec(s) |
| | unavailable = self._outputs.reduce(function(cdcs, output) { |
| | var acodec = output.audio.find('-acodec', 1); |
| | if (acodec && acodec[0] !== 'copy') { |
| | if (!(acodec[0] in encoders) || encoders[acodec[0]].type !== 'audio') { |
| | cdcs.push(acodec[0]); |
| | } |
| | } |
| |
|
| | return cdcs; |
| | }, []); |
| |
|
| | if (unavailable.length === 1) { |
| | return cb(new Error('Audio codec ' + unavailable[0] + ' is not available')); |
| | } else if (unavailable.length > 1) { |
| | return cb(new Error('Audio codecs ' + unavailable.join(', ') + ' are not available')); |
| | } |
| |
|
| | // Video codec(s) |
| | unavailable = self._outputs.reduce(function(cdcs, output) { |
| | var vcodec = output.video.find('-vcodec', 1); |
| | if (vcodec && vcodec[0] !== 'copy') { |
| | if (!(vcodec[0] in encoders) || encoders[vcodec[0]].type !== 'video') { |
| | cdcs.push(vcodec[0]); |
| | } |
| | } |
| |
|
| | return cdcs; |
| | }, []); |
| |
|
| | if (unavailable.length === 1) { |
| | return cb(new Error('Video codec ' + unavailable[0] + ' is not available')); |
| | } else if (unavailable.length > 1) { |
| | return cb(new Error('Video codecs ' + unavailable.join(', ') + ' are not available')); |
| | } |
| |
|
| | cb(); |
| | } |
| | ], callback); |
| | }; |
| | }; |
| | </code></pre> |
| | </article> |
| | </section> |
| |
|
| |
|
| |
|
| |
|
| | </div> |
| |
|
| | <nav> |
| | <h2><a href="index.html">Index</a></h2><ul><li><a href="index.html#installation">Installation</a></li><ul></ul><li><a href="index.html#usage">Usage</a></li><ul><li><a href="index.html#prerequisites">Prerequisites</a></li><li><a href="index.html#creating-an-ffmpeg-command">Creating an FFmpeg command</a></li><li><a href="index.html#specifying-inputs">Specifying inputs</a></li><li><a href="index.html#input-options">Input options</a></li><li><a href="index.html#audio-options">Audio options</a></li><li><a href="index.html#video-options">Video options</a></li><li><a href="index.html#video-frame-size-options">Video frame size options</a></li><li><a href="index.html#specifying-multiple-outputs">Specifying multiple outputs</a></li><li><a href="index.html#output-options">Output options</a></li><li><a href="index.html#miscellaneous-options">Miscellaneous options</a></li><li><a href="index.html#setting-event-handlers">Setting event handlers</a></li><li><a href="index.html#starting-ffmpeg-processing">Starting FFmpeg processing</a></li><li><a href="index.html#controlling-the-ffmpeg-process">Controlling the FFmpeg process</a></li><li><a href="index.html#reading-video-metadata">Reading video metadata</a></li><li><a href="index.html#querying-ffmpeg-capabilities">Querying ffmpeg capabilities</a></li><li><a href="index.html#cloning-an-ffmpegcommand">Cloning an FfmpegCommand</a></li></ul><li><a href="index.html#contributing">Contributing</a></li><ul><li><a href="index.html#code-contributions">Code contributions</a></li><li><a href="index.html#documentation-contributions">Documentation contributions</a></li><li><a href="index.html#updating-the-documentation">Updating the documentation</a></li><li><a href="index.html#running-tests">Running tests</a></li></ul><li><a href="index.html#main-contributors">Main contributors</a></li><ul></ul><li><a href="index.html#license">License</a></li><ul></ul></ul><h3>Classes</h3><ul><li><a href="FfmpegCommand.html">FfmpegCommand</a></li><ul><li> <a href="FfmpegCommand.html#audio-methods">Audio methods</a></li><li> <a href="FfmpegCommand.html#capabilities-methods">Capabilities methods</a></li><li> <a href="FfmpegCommand.html#custom-options-methods">Custom options methods</a></li><li> <a href="FfmpegCommand.html#input-methods">Input methods</a></li><li> <a href="FfmpegCommand.html#metadata-methods">Metadata methods</a></li><li> <a href="FfmpegCommand.html#miscellaneous-methods">Miscellaneous methods</a></li><li> <a href="FfmpegCommand.html#other-methods">Other methods</a></li><li> <a href="FfmpegCommand.html#output-methods">Output methods</a></li><li> <a href="FfmpegCommand.html#processing-methods">Processing methods</a></li><li> <a href="FfmpegCommand.html#video-methods">Video methods</a></li><li> <a href="FfmpegCommand.html#video-size-methods">Video size methods</a></li></ul></ul> |
| | </nav> |
| |
|
| | <br clear="both"> |
| |
|
| | <footer> |
| | Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.0</a> on Sun May 01 2016 12:10:37 GMT+0200 (CEST) |
| | </footer> |
| |
|
| | <script> prettyPrint(); </script> |
| | <script src="scripts/linenumber.js"> </script> |
| | </body> |
| | </html> |
| |
|