229 linhas
6.7 KiB
JavaScript
229 linhas
6.7 KiB
JavaScript
var common = require('../../common');
|
|
var assert = require('assert');
|
|
var test = require('utest');
|
|
var sinon = require('sinon');
|
|
var PngEncoder = require(common.lib + '/video/PngEncoder');
|
|
var EventEmitter = require('events').EventEmitter;
|
|
|
|
|
|
test('PngEncoder', {
|
|
before: function() {
|
|
this.fakeFfmpeg = new EventEmitter();
|
|
|
|
this.fakeFfmpeg.stdin = new EventEmitter();
|
|
this.fakeFfmpeg.stdin.write = sinon.stub();
|
|
this.fakeFfmpeg.stdin.end = sinon.stub();
|
|
|
|
this.fakeFfmpeg.stdout = {pipe: sinon.spy()};
|
|
this.fakeFfmpeg.stderr = {pipe: sinon.spy()};
|
|
|
|
this.fakeSpawn = sinon.stub();
|
|
this.fakeSpawn.returns(this.fakeFfmpeg);
|
|
|
|
this.fakePngSplitter = new EventEmitter();
|
|
|
|
this.fakeFrameRate = 23;
|
|
|
|
this.fakeBuffer1 = new Buffer('123');
|
|
this.fakeBuffer2 = new Buffer('456');
|
|
|
|
this.fakeLog = {};
|
|
|
|
this.encoder = new PngEncoder({
|
|
spawn : this.fakeSpawn,
|
|
frameRate : this.fakeFrameRate,
|
|
pngSplitter : this.fakePngSplitter,
|
|
log : this.fakeLog,
|
|
});
|
|
},
|
|
|
|
'is a writable stream': function() {
|
|
assert.equal(this.encoder.writable, true);
|
|
assert.equal(typeof this.encoder.write, 'function');
|
|
},
|
|
|
|
'is a readable stream': function() {
|
|
assert.equal(this.encoder.readable, true);
|
|
assert.equal(typeof this.encoder.pipe, 'function');
|
|
},
|
|
|
|
'first write() spawns ffmpeg': function() {
|
|
this.encoder.write(new Buffer('foo'));
|
|
|
|
assert.equal(this.fakeSpawn.callCount, 1);
|
|
assert.equal(this.fakeSpawn.getCall(0).args[0], 'ffmpeg');
|
|
|
|
// Another write does not spawn another ffmpeg
|
|
this.encoder.write(new Buffer('bar'));
|
|
assert.equal(this.fakeSpawn.callCount, 1);
|
|
},
|
|
|
|
'write() spawn ffmpeg with the right arguments': function() {
|
|
this.encoder.write(new Buffer('foo'));
|
|
|
|
var args = this.fakeSpawn.getCall(0).args[1];
|
|
|
|
// Read from stdin
|
|
var input = args.indexOf('-i');
|
|
assert.equal(args[input + 1], '-');
|
|
|
|
// Use the image2pipe format
|
|
var format = args.indexOf('-f');
|
|
assert.equal(args[format + 1], 'image2pipe');
|
|
|
|
// Use the png video codec
|
|
var vcodec = args.indexOf('-vcodec');
|
|
assert.equal(args[vcodec + 1], 'png');
|
|
|
|
// Sets the right framerate
|
|
var frameRate = args.indexOf('-r');
|
|
assert.equal(args[frameRate + 1], this.fakeFrameRate);
|
|
|
|
// Pipe to stdout
|
|
assert.equal(args[args.length - 1], '-');
|
|
},
|
|
|
|
'write() pipes ffmpeg.stdout into PngSplitter': function() {
|
|
this.encoder.write(new Buffer('foo'));
|
|
|
|
var stdoutPipe = this.fakeFfmpeg.stdout.pipe;
|
|
assert.equal(stdoutPipe.callCount, 1);
|
|
assert.strictEqual(stdoutPipe.getCall(0).args[0], this.fakePngSplitter);
|
|
},
|
|
|
|
'proxies all pngSplitter "data"': function() {
|
|
var dataSpy = sinon.spy();
|
|
this.encoder.on('data', dataSpy);
|
|
|
|
this.encoder.write(new Buffer('foo'));
|
|
this.fakePngSplitter.emit('data', this.fakeBuffer1);
|
|
|
|
assert.equal(dataSpy.callCount, 1);
|
|
assert.strictEqual(dataSpy.getCall(0).args[0], this.fakeBuffer1);
|
|
|
|
this.fakePngSplitter.emit('data', this.fakeBuffer2);
|
|
assert.equal(dataSpy.callCount, 2);
|
|
assert.strictEqual(dataSpy.getCall(1).args[0], this.fakeBuffer2);
|
|
},
|
|
|
|
'handles ffmpeg spawn error': function() {
|
|
var errorSpy = sinon.spy();
|
|
this.encoder.on('error', errorSpy);
|
|
|
|
this.encoder.write(new Buffer('foo'));
|
|
|
|
// simulate ffmpeg not spawning correctly
|
|
var error = new Error('ENOENT');
|
|
error.code = 'ENOENT';
|
|
this.fakeFfmpeg.stdin.emit('error', new Error('EPIPE'));
|
|
this.fakeFfmpeg.emit('error', error);
|
|
|
|
assert.equal(errorSpy.callCount, 1);
|
|
assert.equal(/ffmpeg.*not found/i.test(errorSpy.getCall(0).args[0]), true);
|
|
},
|
|
|
|
'handles ffmpeg not existing': function() {
|
|
var errorSpy = sinon.spy();
|
|
this.encoder.on('error', errorSpy);
|
|
|
|
this.encoder.write(new Buffer('foo'));
|
|
|
|
// simulate ffmpeg not existing
|
|
this.fakeFfmpeg.stdin.emit('error', new Error('EPIPE'));
|
|
this.fakeFfmpeg.emit('exit', 127);
|
|
|
|
assert.equal(errorSpy.callCount, 1);
|
|
assert.equal(/ffmpeg.*not found/i.test(errorSpy.getCall(0).args[0]), true);
|
|
},
|
|
|
|
'handles ffmpeg exit code > 0': function() {
|
|
var errorSpy = sinon.spy();
|
|
this.encoder.on('error', errorSpy);
|
|
|
|
this.encoder.write(new Buffer('foo'));
|
|
|
|
// simulate an ffmpeg error
|
|
this.fakeFfmpeg.emit('exit', 1);
|
|
|
|
assert.equal(errorSpy.callCount, 1);
|
|
assert.equal(/ffmpeg.*error/i.test(errorSpy.getCall(0).args[0]), true);
|
|
},
|
|
|
|
'handles expected ffmpeg shutdown': function() {
|
|
var endSpy = sinon.spy();
|
|
this.encoder.on('end', endSpy);
|
|
|
|
this.encoder.write(new Buffer('foo'));
|
|
this.encoder.end();
|
|
this.fakeFfmpeg.emit('exit', 0);
|
|
|
|
assert.equal(endSpy.callCount, 1);
|
|
},
|
|
|
|
'handles unexpected ffmpeg shutdown with exit code 0': function() {
|
|
var errorSpy = sinon.spy();
|
|
this.encoder.on('error', errorSpy);
|
|
|
|
this.encoder.write(new Buffer('foo'));
|
|
this.fakeFfmpeg.emit('exit', 0);
|
|
|
|
assert.equal(errorSpy.callCount, 1);
|
|
assert.equal(/unexpected.*ffmpeg/i.test(errorSpy.getCall(0).args[0].message), true);
|
|
},
|
|
|
|
'write() passes all data into ffmpeg.stdin': function() {
|
|
this.encoder.write(this.fakeBuffer1);
|
|
|
|
var stdin = this.fakeFfmpeg.stdin;
|
|
assert.equal(stdin.write.callCount, 1);
|
|
assert.strictEqual(stdin.write.getCall(0).args[0], this.fakeBuffer1);
|
|
|
|
this.encoder.write(this.fakeBuffer2);
|
|
assert.equal(stdin.write.callCount, 2);
|
|
assert.strictEqual(stdin.write.getCall(1).args[0], this.fakeBuffer2);
|
|
},
|
|
|
|
'write() handles ffmpeg backpressure': function() {
|
|
this.fakeFfmpeg.stdin.write.returns(true);
|
|
var r = this.encoder.write(new Buffer('abc'));
|
|
assert.equal(r, true);
|
|
|
|
this.fakeFfmpeg.stdin.write.returns(false);
|
|
r = this.encoder.write(new Buffer('abc'));
|
|
assert.equal(r, false);
|
|
|
|
var drainCalled = false;
|
|
this.encoder.on('drain', function () {
|
|
drainCalled = true;
|
|
});
|
|
this.fakeFfmpeg.stdin.emit('drain');
|
|
assert.ok(drainCalled);
|
|
},
|
|
|
|
'write() pipes ffmpeg stderr to log': function() {
|
|
this.encoder.write(new Buffer('abc'));
|
|
|
|
var stderrPipe = this.fakeFfmpeg.stderr.pipe;
|
|
assert.equal(stderrPipe.callCount, 1);
|
|
assert.strictEqual(stderrPipe.getCall(0).args[0], this.fakeLog);
|
|
},
|
|
|
|
'write() does not pipe to log if not set': function() {
|
|
this.encoder = new PngEncoder({spawn: this.fakeSpawn});
|
|
|
|
this.encoder.write(new Buffer('abc'));
|
|
assert.equal(this.fakeFfmpeg.stderr.pipe.callCount, 0);
|
|
},
|
|
|
|
'end() closes ffmpeg.stdin': function() {
|
|
this.encoder.write(new Buffer('abc'));
|
|
this.encoder.end();
|
|
|
|
assert.equal(this.fakeFfmpeg.stdin.end.callCount, 1);
|
|
},
|
|
|
|
'end() does not do anything if there is no ffmpeg yet': function() {
|
|
this.encoder.end();
|
|
},
|
|
});
|