Download clone/node_modules/fluent-ffmpeg/doc/recipes.js.html from dcrey7/test: direct link, hf CLI and curl.
- Browser
- Download file 17.9 kB
-
https://huggingface.co/spaces/dcrey7/test/resolve/main/clone/node_modules/fluent-ffmpeg/doc/recipes.js.html
- Command line
-
hf download hf://spaces/dcrey7/test/clone/node_modules/fluent-ffmpeg/doc/recipes.js.html
-
curl -L -o recipes.js.html https://huggingface.co/spaces/dcrey7/test/resolve/main/clone/node_modules/fluent-ffmpeg/doc/recipes.js.html
17.9 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>JSDoc: Source: recipes.js</title> | |
| <script src="scripts/prettify/prettify.js"> </script> | |
| <script src="scripts/prettify/lang-css.js"> </script> | |
| <!--[if lt IE 9]> | |
| <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> | |
| <![endif]--> | |
| <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: recipes.js</h1> | |
| <section> | |
| <article> | |
| <pre class="prettyprint source linenums"><code>/*jshint node:true*/ | |
| 'use strict'; | |
| var fs = require('fs'); | |
| var path = require('path'); | |
| var PassThrough = require('stream').PassThrough; | |
| var async = require('async'); | |
| var utils = require('./utils'); | |
| /* | |
| * Useful recipes for commands | |
| */ | |
| module.exports = function recipes(proto) { | |
| /** | |
| * Execute ffmpeg command and save output to a file | |
| * | |
| * @method FfmpegCommand#save | |
| * @category Processing | |
| * @aliases saveToFile | |
| * | |
| * @param {String} output file path | |
| * @return FfmpegCommand | |
| */ | |
| proto.saveToFile = | |
| proto.save = function(output) { | |
| this.output(output).run(); | |
| return this; | |
| }; | |
| /** | |
| * Execute ffmpeg command and save output to a stream | |
| * | |
| * If 'stream' is not specified, a PassThrough stream is created and returned. | |
| * 'options' will be used when piping ffmpeg output to the output stream | |
| * (@see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options) | |
| * | |
| * @method FfmpegCommand#pipe | |
| * @category Processing | |
| * @aliases stream,writeToStream | |
| * | |
| * @param {stream.Writable} [stream] output stream | |
| * @param {Object} [options={}] pipe options | |
| * @return Output stream | |
| */ | |
| proto.writeToStream = | |
| proto.pipe = | |
| proto.stream = function(stream, options) { | |
| if (stream && !('writable' in stream)) { | |
| options = stream; | |
| stream = undefined; | |
| } | |
| if (!stream) { | |
| if (process.version.match(/v0\.8\./)) { | |
| throw new Error('PassThrough stream is not supported on node v0.8'); | |
| } | |
| stream = new PassThrough(); | |
| } | |
| this.output(stream, options).run(); | |
| return stream; | |
| }; | |
| /** | |
| * Generate images from a video | |
| * | |
| * Note: this method makes the command emit a 'filenames' event with an array of | |
| * the generated image filenames. | |
| * | |
| * @method FfmpegCommand#screenshots | |
| * @category Processing | |
| * @aliases takeScreenshots,thumbnail,thumbnails,screenshot | |
| * | |
| * @param {Number|Object} [config=1] screenshot count or configuration object with | |
| * the following keys: | |
| * @param {Number} [config.count] number of screenshots to take; using this option | |
| * takes screenshots at regular intervals (eg. count=4 would take screens at 20%, 40%, | |
| * 60% and 80% of the video length). | |
| * @param {String} [config.folder='.'] output folder | |
| * @param {String} [config.filename='tn.png'] output filename pattern, may contain the following | |
| * tokens: | |
| * - '%s': offset in seconds | |
| * - '%w': screenshot width | |
| * - '%h': screenshot height | |
| * - '%r': screenshot resolution (same as '%wx%h') | |
| * - '%f': input filename | |
| * - '%b': input basename (filename w/o extension) | |
| * - '%i': index of screenshot in timemark array (can be zero-padded by using it like `%000i`) | |
| * @param {Number[]|String[]} [config.timemarks] array of timemarks to take screenshots | |
| * at; each timemark may be a number of seconds, a '[[hh:]mm:]ss[.xxx]' string or a | |
| * 'XX%' string. Overrides 'count' if present. | |
| * @param {Number[]|String[]} [config.timestamps] alias for 'timemarks' | |
| * @param {Boolean} [config.fastSeek] use fast seek (less accurate) | |
| * @param {String} [config.size] screenshot size, with the same syntax as {@link FfmpegCommand#size} | |
| * @param {String} [folder] output folder (legacy alias for 'config.folder') | |
| * @return FfmpegCommand | |
| */ | |
| proto.takeScreenshots = | |
| proto.thumbnail = | |
| proto.thumbnails = | |
| proto.screenshot = | |
| proto.screenshots = function(config, folder) { | |
| var self = this; | |
| var source = this._currentInput.source; | |
| config = config || { count: 1 }; | |
| // Accept a number of screenshots instead of a config object | |
| if (typeof config === 'number') { | |
| config = { | |
| count: config | |
| }; | |
| } | |
| // Accept a second 'folder' parameter instead of config.folder | |
| if (!('folder' in config)) { | |
| config.folder = folder || '.'; | |
| } | |
| // Accept 'timestamps' instead of 'timemarks' | |
| if ('timestamps' in config) { | |
| config.timemarks = config.timestamps; | |
| } | |
| // Compute timemarks from count if not present | |
| if (!('timemarks' in config)) { | |
| if (!config.count) { | |
| throw new Error('Cannot take screenshots: neither a count nor a timemark list are specified'); | |
| } | |
| var interval = 100 / (1 + config.count); | |
| config.timemarks = []; | |
| for (var i = 0; i < config.count; i++) { | |
| config.timemarks.push((interval * (i + 1)) + '%'); | |
| } | |
| } | |
| // Parse size option | |
| if ('size' in config) { | |
| var fixedSize = config.size.match(/^(\d+)x(\d+)$/); | |
| var fixedWidth = config.size.match(/^(\d+)x\?$/); | |
| var fixedHeight = config.size.match(/^\?x(\d+)$/); | |
| var percentSize = config.size.match(/^(\d+)%$/); | |
| if (!fixedSize && !fixedWidth && !fixedHeight && !percentSize) { | |
| throw new Error('Invalid size parameter: ' + config.size); | |
| } | |
| } | |
| // Metadata helper | |
| var metadata; | |
| function getMetadata(cb) { | |
| if (metadata) { | |
| cb(null, metadata); | |
| } else { | |
| self.ffprobe(function(err, meta) { | |
| metadata = meta; | |
| cb(err, meta); | |
| }); | |
| } | |
| } | |
| async.waterfall([ | |
| // Compute percent timemarks if any | |
| function computeTimemarks(next) { | |
| if (config.timemarks.some(function(t) { return ('' + t).match(/^[\d.]+%$/); })) { | |
| if (typeof source !== 'string') { | |
| return next(new Error('Cannot compute screenshot timemarks with an input stream, please specify fixed timemarks')); | |
| } | |
| getMetadata(function(err, meta) { | |
| if (err) { | |
| next(err); | |
| } else { | |
| // Select video stream with the highest resolution | |
| var vstream = meta.streams.reduce(function(biggest, stream) { | |
| if (stream.codec_type === 'video' && stream.width * stream.height > biggest.width * biggest.height) { | |
| return stream; | |
| } else { | |
| return biggest; | |
| } | |
| }, { width: 0, height: 0 }); | |
| if (vstream.width === 0) { | |
| return next(new Error('No video stream in input, cannot take screenshots')); | |
| } | |
| var duration = Number(vstream.duration); | |
| if (isNaN(duration)) { | |
| duration = Number(meta.format.duration); | |
| } | |
| if (isNaN(duration)) { | |
| return next(new Error('Could not get input duration, please specify fixed timemarks')); | |
| } | |
| config.timemarks = config.timemarks.map(function(mark) { | |
| if (('' + mark).match(/^([\d.]+)%$/)) { | |
| return duration * parseFloat(mark) / 100; | |
| } else { | |
| return mark; | |
| } | |
| }); | |
| next(); | |
| } | |
| }); | |
| } else { | |
| next(); | |
| } | |
| }, | |
| // Turn all timemarks into numbers and sort them | |
| function normalizeTimemarks(next) { | |
| config.timemarks = config.timemarks.map(function(mark) { | |
| return utils.timemarkToSeconds(mark); | |
| }).sort(function(a, b) { return a - b; }); | |
| next(); | |
| }, | |
| // Add '_%i' to pattern when requesting multiple screenshots and no variable token is present | |
| function fixPattern(next) { | |
| var pattern = config.filename || 'tn.png'; | |
| if (pattern.indexOf('.') === -1) { | |
| pattern += '.png'; | |
| } | |
| if (config.timemarks.length > 1 && !pattern.match(/%(s|0*i)/)) { | |
| var ext = path.extname(pattern); | |
| pattern = path.join(path.dirname(pattern), path.basename(pattern, ext) + '_%i' + ext); | |
| } | |
| next(null, pattern); | |
| }, | |
| // Replace filename tokens (%f, %b) in pattern | |
| function replaceFilenameTokens(pattern, next) { | |
| if (pattern.match(/%[bf]/)) { | |
| if (typeof source !== 'string') { | |
| return next(new Error('Cannot replace %f or %b when using an input stream')); | |
| } | |
| pattern = pattern | |
| .replace(/%f/g, path.basename(source)) | |
| .replace(/%b/g, path.basename(source, path.extname(source))); | |
| } | |
| next(null, pattern); | |
| }, | |
| // Compute size if needed | |
| function getSize(pattern, next) { | |
| if (pattern.match(/%[whr]/)) { | |
| if (fixedSize) { | |
| return next(null, pattern, fixedSize[1], fixedSize[2]); | |
| } | |
| getMetadata(function(err, meta) { | |
| if (err) { | |
| return next(new Error('Could not determine video resolution to replace %w, %h or %r')); | |
| } | |
| var vstream = meta.streams.reduce(function(biggest, stream) { | |
| if (stream.codec_type === 'video' && stream.width * stream.height > biggest.width * biggest.height) { | |
| return stream; | |
| } else { | |
| return biggest; | |
| } | |
| }, { width: 0, height: 0 }); | |
| if (vstream.width === 0) { | |
| return next(new Error('No video stream in input, cannot replace %w, %h or %r')); | |
| } | |
| var width = vstream.width; | |
| var height = vstream.height; | |
| if (fixedWidth) { | |
| height = height * Number(fixedWidth[1]) / width; | |
| width = Number(fixedWidth[1]); | |
| } else if (fixedHeight) { | |
| width = width * Number(fixedHeight[1]) / height; | |
| height = Number(fixedHeight[1]); | |
| } else if (percentSize) { | |
| width = width * Number(percentSize[1]) / 100; | |
| height = height * Number(percentSize[1]) / 100; | |
| } | |
| next(null, pattern, Math.round(width / 2) * 2, Math.round(height / 2) * 2); | |
| }); | |
| } else { | |
| next(null, pattern, -1, -1); | |
| } | |
| }, | |
| // Replace size tokens (%w, %h, %r) in pattern | |
| function replaceSizeTokens(pattern, width, height, next) { | |
| pattern = pattern | |
| .replace(/%r/g, '%wx%h') | |
| .replace(/%w/g, width) | |
| .replace(/%h/g, height); | |
| next(null, pattern); | |
| }, | |
| // Replace variable tokens in pattern (%s, %i) and generate filename list | |
| function replaceVariableTokens(pattern, next) { | |
| var filenames = config.timemarks.map(function(t, i) { | |
| return pattern | |
| .replace(/%s/g, utils.timemarkToSeconds(t)) | |
| .replace(/%(0*)i/g, function(match, padding) { | |
| var idx = '' + (i + 1); | |
| return padding.substr(0, Math.max(0, padding.length + 1 - idx.length)) + idx; | |
| }); | |
| }); | |
| self.emit('filenames', filenames); | |
| next(null, filenames); | |
| }, | |
| // Create output directory | |
| function createDirectory(filenames, next) { | |
| fs.exists(config.folder, function(exists) { | |
| if (!exists) { | |
| fs.mkdir(config.folder, function(err) { | |
| if (err) { | |
| next(err); | |
| } else { | |
| next(null, filenames); | |
| } | |
| }); | |
| } else { | |
| next(null, filenames); | |
| } | |
| }); | |
| } | |
| ], function runCommand(err, filenames) { | |
| if (err) { | |
| return self.emit('error', err); | |
| } | |
| var count = config.timemarks.length; | |
| var split; | |
| var filters = [split = { | |
| filter: 'split', | |
| options: count, | |
| outputs: [] | |
| }]; | |
| if ('size' in config) { | |
| // Set size to generate size filters | |
| self.size(config.size); | |
| // Get size filters and chain them with 'sizeN' stream names | |
| var sizeFilters = self._currentOutput.sizeFilters.get().map(function(f, i) { | |
| if (i > 0) { | |
| f.inputs = 'size' + (i - 1); | |
| } | |
| f.outputs = 'size' + i; | |
| return f; | |
| }); | |
| // Input last size filter output into split filter | |
| split.inputs = 'size' + (sizeFilters.length - 1); | |
| // Add size filters in front of split filter | |
| filters = sizeFilters.concat(filters); | |
| // Remove size filters | |
| self._currentOutput.sizeFilters.clear(); | |
| } | |
| var first = 0; | |
| for (var i = 0; i < count; i++) { | |
| var stream = 'screen' + i; | |
| split.outputs.push(stream); | |
| if (i === 0) { | |
| first = config.timemarks[i]; | |
| self.seekInput(first); | |
| } | |
| self.output(path.join(config.folder, filenames[i])) | |
| .frames(1) | |
| .map(stream); | |
| if (i > 0) { | |
| self.seek(config.timemarks[i] - first); | |
| } | |
| } | |
| self.complexFilter(filters); | |
| self.run(); | |
| }); | |
| return this; | |
| }; | |
| /** | |
| * Merge (concatenate) inputs to a single file | |
| * | |
| * @method FfmpegCommand#concat | |
| * @category Processing | |
| * @aliases concatenate,mergeToFile | |
| * | |
| * @param {String|Writable} target output file or writable stream | |
| * @param {Object} [options] pipe options (only used when outputting to a writable stream) | |
| * @return FfmpegCommand | |
| */ | |
| proto.mergeToFile = | |
| proto.concatenate = | |
| proto.concat = function(target, options) { | |
| // Find out which streams are present in the first non-stream input | |
| var fileInput = this._inputs.filter(function(input) { | |
| return !input.isStream; | |
| })[0]; | |
| var self = this; | |
| this.ffprobe(this._inputs.indexOf(fileInput), function(err, data) { | |
| if (err) { | |
| return self.emit('error', err); | |
| } | |
| var hasAudioStreams = data.streams.some(function(stream) { | |
| return stream.codec_type === 'audio'; | |
| }); | |
| var hasVideoStreams = data.streams.some(function(stream) { | |
| return stream.codec_type === 'video'; | |
| }); | |
| // Setup concat filter and start processing | |
| self.output(target, options) | |
| .complexFilter({ | |
| filter: 'concat', | |
| options: { | |
| n: self._inputs.length, | |
| v: hasVideoStreams ? 1 : 0, | |
| a: hasAudioStreams ? 1 : 0 | |
| } | |
| }) | |
| .run(); | |
| }); | |
| return this; | |
| }; | |
| }; | |
| </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> | |