Skip to content

Commit

Permalink
Camera: video stream tests
Browse files Browse the repository at this point in the history
Signed-off-by: Rick Waldron <waldron.rick@gmail.com>
  • Loading branch information
rwaldron committed Mar 22, 2016
1 parent 22ffc77 commit fb3d1a9
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 19 deletions.
43 changes: 30 additions & 13 deletions lib/camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,31 +33,39 @@ var cameraDefaults = {
// maps to: ffmpeg -q:v 1-30 (Lower number is better)
quality: 1,
path: '/dev/video0',
output: '/tmp/capture.jpg',
stream: false,
pipe: true,
};

function Camera(options) {
Emitter.call(this);

options = Object.assign({}, cameraDefaults, options || {});
options = options || {};

var settings = Object.assign({}, cameraDefaults, options || {});

if (options.width > cameraDefaults.width ||
options.height > cameraDefaults.height) {
if (settings.width > cameraDefaults.width ||
settings.height > cameraDefaults.height) {
console.log(`Those dimensions are too big, so I'm ignore them.`);
settings.width = cameraDefaults.width;
settings.height = cameraDefaults.height;
}

options.width = cameraDefaults.width;
options.height = cameraDefaults.height;
// We need to look at actual user input, not merged defaults.
if (typeof options.output !== 'undefined') {
settings.pipe = false;
}

var state = {
isStreaming: false,
stream: options.stream,
pipe: options.pipe,
path: options.path,
quality: constrain(options.quality, 0, 1),
width: options.width,
height: options.height,
stream: settings.stream,
pipe: settings.pipe,
path: settings.path,
quality: constrain(settings.quality, 0, 1),
width: settings.width,
height: settings.height,
output: settings.output,
process: null,
};

Expand Down Expand Up @@ -96,6 +104,15 @@ Camera.prototype.capture = function(options) {
state.stream = options.stream;
}

if (typeof options.output !== 'undefined') {
state.output = options.output;
state.pipe = false;
}

if (state.pipe === false && typeof state.output === 'undefined') {
state.output = cameraDefaults.output;
}

var args = [
// Overwrite: yes
'-y',
Expand Down Expand Up @@ -134,7 +151,7 @@ Camera.prototype.capture = function(options) {
if (state.pipe) {
args.push('pipe:1');
} else {
args.push('/tmp/capture.jpg');
args.push(state.output);
}
}

Expand Down Expand Up @@ -171,7 +188,7 @@ Camera.prototype.capture = function(options) {
//
// TODO: allow program specified target locations
//
fs.readFile('/tmp/capture.jpg', (error, data) => {
fs.readFile(state.output, (error, data) => {
this.emit('data', data);
cs.push(data);
cs.push(null);
Expand Down
189 changes: 183 additions & 6 deletions test/unit/camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ exports['av.Camera'] = {
test.done();
},

captureEmitter: function(test) {
captureToEmitter: function(test) {
test.expect(5);

var buffer = new Buffer([0]);
Expand All @@ -60,18 +60,17 @@ exports['av.Camera'] = {
this.emitter.emit('close');
},

capturePipe: function(test) {
// test.expect(5);
captureToPipe: function(test) {
test.expect(1);

var buffer = new Buffer([0]);
var cam = new av.Camera();
var writable = new Writable();

writable._write = function(data) {
test.equal(buffer.equals(data), true);
};
writable._write = function(data) {};

writable.on('pipe', () => {
test.ok(true);
test.done();
});

Expand All @@ -81,6 +80,137 @@ exports['av.Camera'] = {
this.emitter.emit('close');
},

captureSpawnToPipe: function(test) {
test.expect(3);

var cam = new av.Camera();

cam.capture();

test.equal(this.spawn.callCount, 1);
test.equal(this.spawn.lastCall.args[0], 'ffmpeg');
test.deepEqual(this.spawn.lastCall.args[1], [
'-y',
'-v',
'fatal',
'-r',
'30',
'-i',
'/dev/video0',
'-s',
'320x240',
'-q:v',
1,
'-f',
'MJPEG',
'-vframes',
1,
'pipe:1'
]);

test.done();
},

captureToFilePipeFalse: function(test) {
test.expect(3);

var cam = new av.Camera({
// default to /tmp/capture.jpg
pipe: false
});

cam.capture();

test.equal(this.spawn.callCount, 1);
test.equal(this.spawn.lastCall.args[0], 'ffmpeg');
test.deepEqual(this.spawn.lastCall.args[1], [
'-y',
'-v',
'fatal',
'-r',
'30',
'-i',
'/dev/video0',
'-s',
'320x240',
'-q:v',
1,
'-f',
'MJPEG',
'-vframes',
1,
'/tmp/capture.jpg'
]);

test.done();
},

captureToFileOutputFile: function(test) {
test.expect(3);

var cam = new av.Camera({
output: 'foo.jpg'
});

cam.capture();

test.equal(this.spawn.callCount, 1);
test.equal(this.spawn.lastCall.args[0], 'ffmpeg');
test.deepEqual(this.spawn.lastCall.args[1], [
'-y',
'-v',
'fatal',
'-r',
'30',
'-i',
'/dev/video0',
'-s',
'320x240',
'-q:v',
1,
'-f',
'MJPEG',
'-vframes',
1,
'foo.jpg'
]);

test.done();
},

captureToFileOutputFileCaptureCall: function(test) {
test.expect(3);

var cam = new av.Camera();

cam.capture({
output: 'foo.jpg'
});

test.equal(this.spawn.callCount, 1);
test.equal(this.spawn.lastCall.args[0], 'ffmpeg');
test.deepEqual(this.spawn.lastCall.args[1], [
'-y',
'-v',
'fatal',
'-r',
'30',
'-i',
'/dev/video0',
'-s',
'320x240',
'-q:v',
1,
'-f',
'MJPEG',
'-vframes',
1,
'foo.jpg'
]);

test.done();
},

stream: function(test) {
test.expect(4);

Expand All @@ -100,6 +230,53 @@ exports['av.Camera'] = {
test.equal(s instanceof CaptureStream, true);
test.equal(s instanceof Readable, true);

test.done();
},

streamUnaffectedByOutputFile: function(test) {
test.expect(7);

var cam = new av.Camera({
output: 'foo.jpg'
});

var capture = this.sandbox.spy(cam, 'capture');

var s = cam.stream();


test.equal(capture.callCount, 1);
test.deepEqual(capture.lastCall.args[0], {
stream: true,
pipe: true
});

test.equal(s instanceof CaptureStream, true);
test.equal(s instanceof Readable, true);

test.equal(this.spawn.callCount, 1);
test.equal(this.spawn.lastCall.args[0], 'ffmpeg');
test.deepEqual(this.spawn.lastCall.args[1], [
'-y',
'-v',
'fatal',
'-r',
'30',
'-i',
'/dev/video0',
'-s',
'320x240',
'-q:v',
1,
'-f',
'MJPEG',
'-b:v',
'64k',
'-r',
'30',
'pipe:1',
]);

test.done();
}
};

0 comments on commit fb3d1a9

Please sign in to comment.