UNPKG

thing-it-device-camera

Version:

[thing-it-node] Device Plugin for USB and Wifi Cameras.

178 lines (153 loc) 5.26 kB
module.exports = { metadata: { family: "camera", plugin: "usbCamera", label: "USB Camera", tangible: true, actorTypes: [], sensorTypes: [], services: [], configuration: [{ id: "inputDevice", label: "Input Device", type: {id: "string"}, default: "0" }, { id: "inputFormat", label: "Input Format", type: {id: "string"}, default: "avfoundation" }, {id: "bufferFiles", label: "Buffer Files", type: {id: "integer"}, default: "2"}, {id: "videoWidth", label: "Video Width", type: {id: "integer"}, default: "320"}, { id: "videoHeight", label: "Video Height", type: {id: "integer"}, default: "180" }, { id: "latency", label: "Latency", type: {id: "integer"}, default: "5" }] }, create: function (device) { return new UsbCamera(); } }; var q = require('q'); var ffmpeg; /** * */ function UsbCamera() { /** * */ UsbCamera.prototype.start = function () { var deferred = q.defer(); this.state = {}; // Open namespace for web socket connections //var namespaceName = this.node.namespacePrefix + "/devices/" + this.id + "/streams/video"; // //console.log("Namespace: " + namespaceName); // //this.namespace = this.node.io.of(namespaceName); // //this.namespace.on("connection", // function (socket) { // console.log("Stream socket connection established for " // + this.id); // // this.maxFiles = this.configuration.bufferFiles; // this.videoSize = "" + this.configuration.videoWidth + "x" + this.configuration.videoHeight; // this.fileIndex = 0; // this.state = {video: "0"}; // // this.pushCameraInput(); // }.bind(this)); //this.namespace.on("disconnect", function (socket) { // console.log("Stream socket disconnected established for " // + this.id); //}.bind(this)); // this.socketStream = socketStream.create(this.namespace); if (this.isSimulated()) { deferred.resolve(); setInterval(function () { this.state = {video: "" + new Date().getMilliseconds()}; this.publishStateChange(); }.bind(this), this.configuration.latency * 1000); } else { if (!ffmpeg) { ffmpeg = require("fluent-ffmpeg"); } this.maxFiles = this.configuration.bufferFiles; this.videoSize = "" + this.configuration.videoWidth + "x" + this.configuration.videoHeight; this.fileIndex = 0; this.state = {video: "0"}; this.streamChunk(); deferred.resolve(); } return deferred.promise; }; /** * */ UsbCamera.prototype.pushCameraInput = function () { var streamHeader = new Buffer(8); streamHeader.write("jsmp"); streamHeader.writeUInt16BE(this.configuration.videoWidth, 4); streamHeader.writeUInt16BE(this.configuration.videoHeight, 6); this.socketStream.write(streamHeader); ffmpeg().input(this.configuration.inputDevice).inputFormat(this.configuration.inputFormat) .outputFormat("mpeg1video").size(this.videoSize) .on('end', function () { }.bind(this)) .on('error', function (error) { console.error(error.message); }).pipe(this.socketStream, {end: true}); }; /** * */ UsbCamera.prototype.streamChunk = function () { ffmpeg().input(this.configuration.inputDevice).inputFormat(this.configuration.inputFormat) .duration(this.configuration.latency).size(this.videoSize) .on('end', function () { this.state = {video: "" + this.fileIndex}; this.publishStateChange(); this.fileIndex = (this.fileIndex + 1) % this.maxFiles; this.streamChunk(); }.bind(this)) .on('error', function (error) { console.error(error.message); }).save(this.getStreamingFilePath(this.fileIndex)); }; /** * */ UsbCamera.prototype.getStreamingFilePath = function (stream) { if (this.isSimulated()) { return __dirname + "/data/spaceship.m4v"; } else { return __dirname + "/../../../" + this.node.options.dataDirectory + "/" + this.id + "-" + stream + ".m4v"; } }; /** * */ UsbCamera.prototype.pipeStream = function (req, res, stream) { this.pipeFile(req, res, this.getStreamingFilePath(stream), "video/mp4"); }; /** * */ UsbCamera.prototype.setState = function (state) { this.state = state; }; /** * */ UsbCamera.prototype.getState = function () { return this.state; }; }