diff --git a/lib/options/inputs.js b/lib/options/inputs.js index 804a21a3..61e1e174 100644 --- a/lib/options/inputs.js +++ b/lib/options/inputs.js @@ -147,6 +147,10 @@ module.exports = function(proto) { throw new Error('No input specified'); } + if (typeof seek === 'number') { + seek = utils.formatNumberForCall(seek); + } + this._currentInput.options('-ss', seek); return this; diff --git a/lib/options/output.js b/lib/options/output.js index da4f7711..8dae8b2c 100644 --- a/lib/options/output.js +++ b/lib/options/output.js @@ -88,6 +88,9 @@ module.exports = function(proto) { */ proto.seekOutput = proto.seek = function(seek) { + if (typeof seek === 'number') { + seek = utils.formatNumberForCall(seek); + } this._currentOutput.options('-ss', seek); return this; }; @@ -106,6 +109,9 @@ module.exports = function(proto) { proto.withDuration = proto.setDuration = proto.duration = function(duration) { + if (typeof duration === 'number') { + duration = utils.formatNumberForCall(duration); + } this._currentOutput.options('-t', duration); return this; }; diff --git a/lib/utils.js b/lib/utils.js index 3b1b2674..ddc4bcff 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -40,6 +40,11 @@ function parseProgressLine(line) { return progress; } +const numberFormatter = new Intl.NumberFormat('en-US', { + useGrouping: false, + // 10 digits to provide ample precision for high samplerate audio + maximumFractionDigits: 10, +}); var utils = module.exports = { isWindows: isWindows, @@ -374,7 +379,7 @@ var utils = module.exports = { * - close() : prevents further append() calls and does a last call to callbacks * - callback(cb) : calls cb for each line (incl. those already in the ring) * - * @param {Numebr} maxLines maximum number of lines to store (<= 0 for unlimited) + * @param {Number} maxLines maximum number of lines to store (<= 0 for unlimited) */ linesRing: function(maxLines) { var cbs = []; @@ -451,5 +456,16 @@ var utils = module.exports = { closed = true; } }; + }, + + /** + * Convert number to decimal notation. Javascript floating point numbers are + * sometimes represented in scientific notation, and ffmpeg cannot handle + * that format. + * @param {Number} num number to format for call to ffmpeg + * @returns {String} string representation of number in decimal notation + */ + formatNumberForCall: function (num) { + return numberFormatter.format(num); } }; diff --git a/test/args.test.js b/test/args.test.js index a57f0d73..fe9ffd3c 100644 --- a/test/args.test.js +++ b/test/args.test.js @@ -432,7 +432,7 @@ describe('Command', function() { if(args.indexOf('-loop') != -1 || args.indexOf('-loop_output') != -1){ args.indexOf('-t').should.above(-1); - args.indexOf(120).should.above(-1); + args.indexOf('120').should.above(-1); done(); } else{ @@ -607,6 +607,28 @@ describe('Command', function() { done(); }); }); + + it('should apply start time converted from scientific notation (0)', function(done) { + new Ffmpeg({ source: this.testfile, logger: testhelper.logger }) + .setStartTime(1e-15) + ._test_getArgs(function(args, err) { + testhelper.logArgError(err); + assert.ok(!err); + args.indexOf('-ss').should.equal(args.indexOf('0') - 1); + done(); + }); + }); + + it('should apply start time converted from scientific notation (nonzero)', function(done) { + new Ffmpeg({ source: this.testfile, logger: testhelper.logger }) + .setStartTime(1.234567e-9) + ._test_getArgs(function(args, err) { + testhelper.logArgError(err); + assert.ok(!err); + args.indexOf('-ss').should.equal(args.indexOf('0.0000000012') - 1); + done(); + }); + }); }); describe('setDuration', function() { @@ -618,7 +640,29 @@ describe('Command', function() { assert.ok(!err); args.indexOf('-t').should.above(-1); - args.indexOf(10).should.above(-1); + args.indexOf('10').should.above(-1); + done(); + }); + }); + + it('should apply duration converted from scientific notation (0)', function(done) { + new Ffmpeg({ source: this.testfile, logger: testhelper.logger }) + .setDuration(1e-15) + ._test_getArgs(function(args, err) { + testhelper.logArgError(err); + assert.ok(!err); + args.indexOf('-t').should.equal(args.indexOf('0') - 1); + done(); + }); + }); + + it('should apply duration converted from scientific notation (nonzero)', function(done) { + new Ffmpeg({ source: this.testfile, logger: testhelper.logger }) + .setDuration(1.234567e-9) + ._test_getArgs(function(args, err) { + testhelper.logArgError(err); + assert.ok(!err); + args.indexOf('-t').should.equal(args.indexOf('0.0000000012') - 1); done(); }); }); diff --git a/test/utils.test.js b/test/utils.test.js index 5c987404..288c68e1 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -203,4 +203,26 @@ describe('Utilities', function() { ring.get().should.equal('foo\nbar\nbazfoo\nbar'); }); }); + + describe('Format number for call', function() { + it('formats decimal notation number as string', function() { + utils.formatNumberForCall(0).should.equal('0'); + utils.formatNumberForCall(1).should.equal('1'); + utils.formatNumberForCall(1.5).should.equal('1.5'); + utils.formatNumberForCall(-1.5).should.equal('-1.5'); + }); + + it('truncates numbers to 10 decimal places', function() { + utils.formatNumberForCall(234222.2333333333334).should.equal('234222.2333333333'); + utils.formatNumberForCall(234222.2337777777774).should.equal('234222.2337777778'); + }) + + it('formats scientific notation number as decimal', function() { + utils.formatNumberForCall(1e2).should.equal('100'); + utils.formatNumberForCall(1e-5).should.equal('0.00001'); + utils.formatNumberForCall(-1e-5).should.equal('-0.00001'); + utils.formatNumberForCall(5.684341886080802e-14).should.equal('0'); + utils.formatNumberForCall(-5.684341886080802e-14).should.equal('-0'); + }); + }) });