123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <title>JSDoc: Source: ffprobe.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: ffprobe.js</h1>
-
-
- <section>
- <article>
- <pre class="prettyprint source linenums"><code>/*jshint node:true, laxcomma:true*/
- 'use strict';
- var spawn = require('child_process').spawn;
- function legacyTag(key) { return key.match(/^TAG:/); }
- function legacyDisposition(key) { return key.match(/^DISPOSITION:/); }
- function parseFfprobeOutput(out) {
- var lines = out.split(/\r\n|\r|\n/);
- lines = lines.filter(function (line) {
- return line.length > 0;
- });
- var data = {
- streams: [],
- format: {},
- chapters: []
- };
- function parseBlock(name) {
- var data = {};
- var line = lines.shift();
- while (typeof line !== 'undefined') {
- if (line.toLowerCase() == '[/'+name+']') {
- return data;
- } else if (line.match(/^\[/)) {
- line = lines.shift();
- continue;
- }
- var kv = line.match(/^([^=]+)=(.*)$/);
- if (kv) {
- if (!(kv[1].match(/^TAG:/)) && kv[2].match(/^[0-9]+(\.[0-9]+)?$/)) {
- data[kv[1]] = Number(kv[2]);
- } else {
- data[kv[1]] = kv[2];
- }
- }
- line = lines.shift();
- }
- return data;
- }
- var line = lines.shift();
- while (typeof line !== 'undefined') {
- if (line.match(/^\[stream/i)) {
- var stream = parseBlock('stream');
- data.streams.push(stream);
- } else if (line.match(/^\[chapter/i)) {
- var chapter = parseBlock('chapter');
- data.chapters.push(chapter);
- } else if (line.toLowerCase() === '[format]') {
- data.format = parseBlock('format');
- }
- line = lines.shift();
- }
- return data;
- }
- module.exports = function(proto) {
- /**
- * A callback passed to the {@link FfmpegCommand#ffprobe} method.
- *
- * @callback FfmpegCommand~ffprobeCallback
- *
- * @param {Error|null} err error object or null if no error happened
- * @param {Object} ffprobeData ffprobe output data; this object
- * has the same format as what the following command returns:
- *
- * `ffprobe -print_format json -show_streams -show_format INPUTFILE`
- * @param {Array} ffprobeData.streams stream information
- * @param {Object} ffprobeData.format format information
- */
- /**
- * Run ffprobe on last specified input
- *
- * @method FfmpegCommand#ffprobe
- * @category Metadata
- *
- * @param {?Number} [index] 0-based index of input to probe (defaults to last input)
- * @param {?String[]} [options] array of output options to return
- * @param {FfmpegCommand~ffprobeCallback} callback callback function
- *
- */
- proto.ffprobe = function() {
- var input, index = null, options = [], callback;
- // the last argument should be the callback
- var callback = arguments[arguments.length - 1];
- var ended = false
- function handleCallback(err, data) {
- if (!ended) {
- ended = true;
- callback(err, data);
- }
- };
- // map the arguments to the correct variable names
- switch (arguments.length) {
- case 3:
- index = arguments[0];
- options = arguments[1];
- break;
- case 2:
- if (typeof arguments[0] === 'number') {
- index = arguments[0];
- } else if (Array.isArray(arguments[0])) {
- options = arguments[0];
- }
- break;
- }
- if (index === null) {
- if (!this._currentInput) {
- return handleCallback(new Error('No input specified'));
- }
- input = this._currentInput;
- } else {
- input = this._inputs[index];
- if (!input) {
- return handleCallback(new Error('Invalid input index'));
- }
- }
- // Find ffprobe
- this._getFfprobePath(function(err, path) {
- if (err) {
- return handleCallback(err);
- } else if (!path) {
- return handleCallback(new Error('Cannot find ffprobe'));
- }
- var stdout = '';
- var stdoutClosed = false;
- var stderr = '';
- var stderrClosed = false;
- // Spawn ffprobe
- var src = input.isStream ? 'pipe:0' : input.source;
- var ffprobe = spawn(path, ['-show_streams', '-show_format'].concat(options, src));
- if (input.isStream) {
- // Skip errors on stdin. These get thrown when ffprobe is complete and
- // there seems to be no way hook in and close stdin before it throws.
- ffprobe.stdin.on('error', function(err) {
- if (['ECONNRESET', 'EPIPE'].indexOf(err.code) >= 0) { return; }
- handleCallback(err);
- });
- // Once ffprobe's input stream closes, we need no more data from the
- // input
- ffprobe.stdin.on('close', function() {
- input.source.pause();
- input.source.unpipe(ffprobe.stdin);
- });
- input.source.pipe(ffprobe.stdin);
- }
- ffprobe.on('error', callback);
- // Ensure we wait for captured streams to end before calling callback
- var exitError = null;
- function handleExit(err) {
- if (err) {
- exitError = err;
- }
- if (processExited && stdoutClosed && stderrClosed) {
- if (exitError) {
- if (stderr) {
- exitError.message += '\n' + stderr;
- }
- return handleCallback(exitError);
- }
- // Process output
- var data = parseFfprobeOutput(stdout);
- // Handle legacy output with "TAG:x" and "DISPOSITION:x" keys
- [data.format].concat(data.streams).forEach(function(target) {
- if (target) {
- var legacyTagKeys = Object.keys(target).filter(legacyTag);
- if (legacyTagKeys.length) {
- target.tags = target.tags || {};
- legacyTagKeys.forEach(function(tagKey) {
- target.tags[tagKey.substr(4)] = target[tagKey];
- delete target[tagKey];
- });
- }
- var legacyDispositionKeys = Object.keys(target).filter(legacyDisposition);
- if (legacyDispositionKeys.length) {
- target.disposition = target.disposition || {};
- legacyDispositionKeys.forEach(function(dispositionKey) {
- target.disposition[dispositionKey.substr(12)] = target[dispositionKey];
- delete target[dispositionKey];
- });
- }
- }
- });
- handleCallback(null, data);
- }
- }
- // Handle ffprobe exit
- var processExited = false;
- ffprobe.on('exit', function(code, signal) {
- processExited = true;
- if (code) {
- handleExit(new Error('ffprobe exited with code ' + code));
- } else if (signal) {
- handleExit(new Error('ffprobe was killed with signal ' + signal));
- } else {
- handleExit();
- }
- });
- // Handle stdout/stderr streams
- ffprobe.stdout.on('data', function(data) {
- stdout += data;
- });
- ffprobe.stdout.on('close', function() {
- stdoutClosed = true;
- handleExit();
- });
- ffprobe.stderr.on('data', function(data) {
- stderr += data;
- });
- ffprobe.stderr.on('close', function() {
- stderrClosed = true;
- handleExit();
- });
- });
- };
- };
- </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>
|