@@ -36,22 +36,32 @@ <h1 class="page-title">Source: ffprobe.js</h1>
3636
3737function parseFfprobeOutput(out) {
3838 var lines = out.split(/\r\n|\r|\n/);
39+
40+ lines = lines.filter(function (line) {
41+ return line.length > 0;
42+ });
43+
3944 var data = {
40- streams: []
45+ streams: [],
46+ format: {},
47+ chapters: []
4148 };
4249
43- function parseBlock() {
50+ function parseBlock(name ) {
4451 var data = {};
4552
4653 var line = lines.shift();
47- while (line) {
48- if (line.match(/^\[\//) ) {
54+ while (typeof line !== 'undefined' ) {
55+ if (line.toLowerCase() == '[/'+name+']' ) {
4956 return data;
57+ } else if (line.match(/^\[/)) {
58+ line = lines.shift();
59+ continue;
5060 }
5161
5262 var kv = line.match(/^([^=]+)=(.*)$/);
5363 if (kv) {
54- if (kv[2].match(/^[0-9]+(.[0-9]+)?$/)) {
64+ if (!( kv[1].match(/^TAG:/)) && kv[ 2].match(/^[0-9]+(\ .[0-9]+)?$/)) {
5565 data[kv[1]] = Number(kv[2]);
5666 } else {
5767 data[kv[1]] = kv[2];
@@ -65,12 +75,15 @@ <h1 class="page-title">Source: ffprobe.js</h1>
6575 }
6676
6777 var line = lines.shift();
68- while (line) {
69- if (line === '[STREAM]' ) {
70- var stream = parseBlock();
78+ while (typeof line !== 'undefined' ) {
79+ if (line.match(/^\[stream/i) ) {
80+ var stream = parseBlock('stream' );
7181 data.streams.push(stream);
72- } else if (line === '[FORMAT]') {
73- data.format = parseBlock();
82+ } else if (line.match(/^\[chapter/i)) {
83+ var chapter = parseBlock('chapter');
84+ data.chapters.push(chapter);
85+ } else if (line.toLowerCase() === '[format]') {
86+ data.format = parseBlock('format');
7487 }
7588
7689 line = lines.shift();
@@ -102,39 +115,61 @@ <h1 class="page-title">Source: ffprobe.js</h1>
102115 * @method FfmpegCommand#ffprobe
103116 * @category Metadata
104117 *
105- * @param {Number} [index] 0-based index of input to probe (defaults to last input)
118+ * @param {?Number} [index] 0-based index of input to probe (defaults to last input)
119+ * @param {?String[]} [options] array of output options to return
106120 * @param {FfmpegCommand~ffprobeCallback} callback callback function
107121 *
108122 */
109- proto.ffprobe = function(index, callback) {
110- var input;
123+ proto.ffprobe = function() {
124+ var input, index = null, options = [], callback;
125+
126+ // the last argument should be the callback
127+ var callback = arguments[arguments.length - 1];
128+
129+ var ended = false
130+ function handleCallback(err, data) {
131+ if (!ended) {
132+ ended = true;
133+ callback(err, data);
134+ }
135+ };
136+
137+ // map the arguments to the correct variable names
138+ switch (arguments.length) {
139+ case 3:
140+ index = arguments[0];
141+ options = arguments[1];
142+ break;
143+ case 2:
144+ if (typeof arguments[0] === 'number') {
145+ index = arguments[0];
146+ } else if (Array.isArray(arguments[0])) {
147+ options = arguments[0];
148+ }
149+ break;
150+ }
111151
112- if (typeof callback === 'undefined') {
113- callback = index;
114152
153+ if (index === null) {
115154 if (!this._currentInput) {
116- return callback (new Error('No input specified'));
155+ return handleCallback (new Error('No input specified'));
117156 }
118157
119158 input = this._currentInput;
120159 } else {
121160 input = this._inputs[index];
122161
123162 if (!input) {
124- return callback (new Error('Invalid input index'));
163+ return handleCallback (new Error('Invalid input index'));
125164 }
126165 }
127166
128- if (!input.isFile) {
129- return callback(new Error('Cannot run ffprobe on non-file input'));
130- }
131-
132167 // Find ffprobe
133168 this._getFfprobePath(function(err, path) {
134169 if (err) {
135- return callback (err);
170+ return handleCallback (err);
136171 } else if (!path) {
137- return callback (new Error('Cannot find ffprobe'));
172+ return handleCallback (new Error('Cannot find ffprobe'));
138173 }
139174
140175 var stdout = '';
@@ -143,15 +178,28 @@ <h1 class="page-title">Source: ffprobe.js</h1>
143178 var stderrClosed = false;
144179
145180 // Spawn ffprobe
146- var ffprobe = spawn(path, [
147- '-show_streams',
148- '-show_format',
149- input.source
150- ]);
151-
152- ffprobe.on('error', function(err) {
153- callback(err);
154- });
181+ var src = input.isStream ? 'pipe:0' : input.source;
182+ var ffprobe = spawn(path, ['-show_streams', '-show_format'].concat(options, src));
183+
184+ if (input.isStream) {
185+ // Skip errors on stdin. These get thrown when ffprobe is complete and
186+ // there seems to be no way hook in and close stdin before it throws.
187+ ffprobe.stdin.on('error', function(err) {
188+ if (['ECONNRESET', 'EPIPE'].indexOf(err.code) > = 0) { return; }
189+ handleCallback(err);
190+ });
191+
192+ // Once ffprobe's input stream closes, we need no more data from the
193+ // input
194+ ffprobe.stdin.on('close', function() {
195+ input.source.pause();
196+ input.source.unpipe(ffprobe.stdin);
197+ });
198+
199+ input.source.pipe(ffprobe.stdin);
200+ }
201+
202+ ffprobe.on('error', callback);
155203
156204 // Ensure we wait for captured streams to end before calling callback
157205 var exitError = null;
@@ -166,38 +214,40 @@ <h1 class="page-title">Source: ffprobe.js</h1>
166214 exitError.message += '\n' + stderr;
167215 }
168216
169- return callback (exitError);
217+ return handleCallback (exitError);
170218 }
171219
172220 // Process output
173221 var data = parseFfprobeOutput(stdout);
174222
175223 // Handle legacy output with "TAG:x" and "DISPOSITION:x" keys
176224 [data.format].concat(data.streams).forEach(function(target) {
177- var legacyTagKeys = Object.keys(target).filter(legacyTag);
225+ if (target) {
226+ var legacyTagKeys = Object.keys(target).filter(legacyTag);
178227
179- if (legacyTagKeys.length) {
180- target.tags = target.tags || {};
228+ if (legacyTagKeys.length) {
229+ target.tags = target.tags || {};
181230
182- legacyTagKeys.forEach(function(tagKey) {
183- target.tags[tagKey.substr(4)] = target[tagKey];
184- delete target[tagKey];
185- });
186- }
231+ legacyTagKeys.forEach(function(tagKey) {
232+ target.tags[tagKey.substr(4)] = target[tagKey];
233+ delete target[tagKey];
234+ });
235+ }
187236
188- var legacyDispositionKeys = Object.keys(target).filter(legacyDisposition);
237+ var legacyDispositionKeys = Object.keys(target).filter(legacyDisposition);
189238
190- if (legacyDispositionKeys.length) {
191- target.disposition = target.disposition || {};
239+ if (legacyDispositionKeys.length) {
240+ target.disposition = target.disposition || {};
192241
193- legacyDispositionKeys.forEach(function(dispositionKey) {
194- target.disposition[dispositionKey.substr(12)] = target[dispositionKey];
195- delete target[dispositionKey];
196- });
242+ legacyDispositionKeys.forEach(function(dispositionKey) {
243+ target.disposition[dispositionKey.substr(12)] = target[dispositionKey];
244+ delete target[dispositionKey];
245+ });
246+ }
197247 }
198248 });
199249
200- callback (null, data);
250+ handleCallback (null, data);
201251 }
202252 }
203253
@@ -236,7 +286,6 @@ <h1 class="page-title">Source: ffprobe.js</h1>
236286 });
237287 };
238288};
239-
240289</ code > </ pre >
241290 </ article >
242291 </ section >
@@ -253,7 +302,7 @@ <h2><a href="index.html">Index</a></h2><ul><li><a href="index.html#installation"
253302< br clear ="both ">
254303
255304< footer >
256- Documentation generated by < a href ="https://github.com/jsdoc3/jsdoc "> JSDoc 3.3.0-alpha5 </ a > on Tue Jul 08 2014 21:22:19 GMT+0200 (CEST)
305+ 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)
257306</ footer >
258307
259308< script > prettyPrint ( ) ; </ script >
0 commit comments