init
This commit is contained in:
commit
b799070fd1
|
@ -0,0 +1,39 @@
|
|||
# PTZOptics Node Server
|
||||
|
||||
The PTZOptics Node Server is a simple skeleton Express server to control your PTZOptics camera via visca commands.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You need to have at least [Node.js version: 8.12.0](https://nodejs.org/en/download/), [MongoDB version: 4.0.3](https://www.mongodb.com/download-center?initial=true#community), and a [PTZOptics camera](https://ptzoptics.com/).
|
||||
|
||||
## Installing
|
||||
1. Configure your PTZOptics camera to your local network. [PTZOptics Knowledge Base](https://help.ptzoptics.com/support/solutions/folders/13000001062)
|
||||
2. Clone this repo and then extract to your preferred location
|
||||
3. Update the mongoDB connection information inside `/app/config.json`.
|
||||
|
||||
```
|
||||
{
|
||||
connectionString: "mongodb://your-mongo-address/db-name",
|
||||
secret: "your db-secret"
|
||||
}
|
||||
```
|
||||
|
||||
4. Start the server
|
||||
|
||||
`cd /The/path/to/the/repo`
|
||||
`npm start`
|
||||
|
||||
5. Head to `http://localhost:4000`
|
||||
6. Click 'Add Camera' and enter your camera's information.
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork it!
|
||||
2. Create your feature branch: `git checkout -b my-new-feature`
|
||||
3. Commit your changes: `git commit -m 'Add some feature'`
|
||||
4. Push to the branch: `git push origin my-new-feature`
|
||||
5. Submit a pull request :D
|
||||
|
||||
## Authors
|
||||
|
||||
[**PTZOptics**](https://github.com/PTZOptics)
|
|
@ -0,0 +1,180 @@
|
|||
/*jshint esversion: 6 */
|
||||
const path = require('path');
|
||||
const http = require('http');
|
||||
const tcpPortUsed =require('tcp-port-used');
|
||||
const db = require(path.resolve(__dirname, './db.js'));
|
||||
const Camera = db.Camera;
|
||||
|
||||
module.exports = {
|
||||
getDeviceModel,
|
||||
checkPortUse,
|
||||
createNewCameraStreamPort
|
||||
};
|
||||
|
||||
async function checkPortUse(port) {
|
||||
return tcpPortUsed.check(port, '127.0.0.1')
|
||||
.then((inuse) => {
|
||||
return inuse;
|
||||
})
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
async function getDeviceModel(ip) {
|
||||
const options = {
|
||||
hostname: ip,
|
||||
path: '/cgi-bin/param.cgi?get_serial_number',
|
||||
method: 'GET'
|
||||
};
|
||||
return sendCgiReq(options)
|
||||
.then((res) => {
|
||||
const rawData = res.toString().replace(/\n/g, '').toUpperCase();
|
||||
return calcCamModel(rawData, rawData.substring(0, 1), rawData.substring(0, 2))
|
||||
.then(res => {
|
||||
return res;
|
||||
})
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
async function calcCamModel(serial, first_letter, twoFirst_letter) {
|
||||
let model = '';
|
||||
// Check 12x
|
||||
if (["1", "A", "B", "C", "D", "N", "O"].includes(first_letter)) {
|
||||
model = "PT12X-";
|
||||
(first_letter === "1") ? model += serial.slice(3, 6) + "-XX-" + serial.slice(8, 10) + checkPoe(serial.slice(10)) : model += newSerialAnsBuilder(serial);
|
||||
}
|
||||
|
||||
// Check 20x
|
||||
if (["2", "E", "F", "G", "H", "P", "Q"].includes(first_letter) && twoFirst_letter !== "PT" ) {
|
||||
model = "PT20X-";
|
||||
(first_letter === "2") ? model += serial.slice(3, 6) + "-XX-" + serial.slice(8, 10) + checkPoe(serial.slice(10)) : model += newSerialAnsBuilder(serial);
|
||||
}
|
||||
|
||||
// Check 30x
|
||||
if (["W", "X", "R", "S"].includes(first_letter)) {
|
||||
model = "PT30X-" + newSerialAnsBuilder(serial);
|
||||
}
|
||||
|
||||
// Check zcams
|
||||
if (["J", "U", "I", "T"].includes(first_letter)) {
|
||||
(["J", "U"].includes(first_letter)) ? model = "PT20X-ZCAM-" : model = "PTVL-ZCAM";
|
||||
}
|
||||
|
||||
if ('PT' == twoFirst_letter) {
|
||||
(serial.slice(0, 4) === "PTVL") ? model = "PTVL-ZCAM-" : model = "PT20X-ZCAM-";
|
||||
}
|
||||
return [model, serial];
|
||||
}
|
||||
|
||||
function newSerialAnsBuilder(serial) {
|
||||
let ans = '';
|
||||
switch(serial.substring(0, 1)) {
|
||||
// 12X
|
||||
case "A":
|
||||
case "B":
|
||||
ans = "SDI-XX-G2" + checkPoe(serial.slice(1));
|
||||
break;
|
||||
|
||||
case "C":
|
||||
case "D":
|
||||
ans = "USB-XX-G2";
|
||||
break;
|
||||
|
||||
case "N":
|
||||
case "O":
|
||||
ans = "SDI-XX-G2 POE";
|
||||
break;
|
||||
|
||||
// 20X
|
||||
case "E":
|
||||
case "F":
|
||||
ans = "SDI-XX-G2" + checkPoe(serial.slice(1));
|
||||
break;
|
||||
|
||||
case "G":
|
||||
case "H":
|
||||
ans = "USB-XX-G2";
|
||||
break;
|
||||
|
||||
case "P":
|
||||
case "Q":
|
||||
ans = "SDI-XX-G2 POE";
|
||||
break;
|
||||
|
||||
// 30X
|
||||
case "W":
|
||||
case "X":
|
||||
ans = "SDI-XX-G2 POE";
|
||||
break;
|
||||
|
||||
case "R":
|
||||
case "S":
|
||||
ans = "NDI-XX-G2";
|
||||
break;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
function checkPoe (serialNum) {
|
||||
if (serialNum <= "B1025000") {
|
||||
return '';
|
||||
} else if (serialNum >= "B1025001" && serialNum <= "D0129000") {
|
||||
return "-POE";
|
||||
} else if(serialNum >= "D0129001") {
|
||||
return "-POE";
|
||||
}
|
||||
}
|
||||
|
||||
async function createNewCameraStreamPort() {
|
||||
let port = 5000;
|
||||
let cameraStreamPorts;
|
||||
try {
|
||||
// Returns all saved camera stream ports
|
||||
cameraStreamPorts = await currentCameraStreamPorts();
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
while (cameraStreamPorts.includes(port)) {
|
||||
++port;
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
async function currentCameraStreamPorts() {
|
||||
return Camera.find().select('streamPort').lean()
|
||||
.then((cameras) => {
|
||||
return cameras.map((camera) => {
|
||||
return camera.streamPort;
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
function sendCgiReq(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
const req = http.request(options, (res) => {
|
||||
let rawData = '';
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', (chunk) => {
|
||||
rawData += chunk;
|
||||
});
|
||||
res.on('end', () => {
|
||||
resolve(rawData);
|
||||
});
|
||||
});
|
||||
req.on('error', function(err) {
|
||||
reject(err);
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/*jshint esversion: 6 */
|
||||
const path = require('path');
|
||||
const config = require(path.resolve(__dirname, '../config.json'));
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
mongoose.connect(config.connectionString, {useNewUrlParser: true });
|
||||
mongoose.Promise = global.Promise;
|
||||
|
||||
module.exports = {
|
||||
Camera: require('../camera/camera.model')
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
module.exports = errorHandler;
|
||||
|
||||
function errorHandler(err, req, res, next) {
|
||||
console.log(err);
|
||||
if (typeof err === 'string') {
|
||||
return res.status(409).json({message: err});
|
||||
}
|
||||
return res.status(500).json({message: err.message});
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*jshint esversion: 6 */
|
||||
|
||||
module.exports = {
|
||||
translateDirection,
|
||||
hexStrToNum,
|
||||
numToHexStr,
|
||||
sanitizeSpeed,
|
||||
getCurrentPos
|
||||
};
|
||||
|
||||
function translateDirection(direction) {
|
||||
let hexStr;
|
||||
switch(direction.toLowerCase()) {
|
||||
case "stop":
|
||||
hexStr = "0303FF";
|
||||
break;
|
||||
case "up":
|
||||
hexStr = "0301FF";
|
||||
break;
|
||||
case "down":
|
||||
hexStr = "0302FF";
|
||||
break;
|
||||
case "right":
|
||||
hexStr = "0203FF";
|
||||
break;
|
||||
case "left":
|
||||
hexStr = "0103FF";
|
||||
break;
|
||||
case "upleft":
|
||||
hexStr = "0101FF";
|
||||
break;
|
||||
case "upright":
|
||||
hexStr = "0201FF";
|
||||
break;
|
||||
case "downleft":
|
||||
hexStr = "0102FF";
|
||||
break;
|
||||
case "downright":
|
||||
hexStr = "0202FF";
|
||||
break;
|
||||
default:
|
||||
throw "The direction " + direction + " is not a valid movement direction";
|
||||
}
|
||||
return hexStr;
|
||||
}
|
||||
|
||||
function hexStrToNum(str) {
|
||||
return parseInt(str, 16);
|
||||
}
|
||||
|
||||
function numToHexStr(num) {
|
||||
if (num == 0) {
|
||||
return '00';
|
||||
}
|
||||
|
||||
if (typeof num === 'string') {
|
||||
num = parseInt(num);
|
||||
}
|
||||
|
||||
return num.toString(16).toUpperCase().split('').reduce(function(str, char) {
|
||||
return '0' + char;
|
||||
});
|
||||
}
|
||||
|
||||
function sanitizeSpeed(pan, tilt) {
|
||||
let sanitizedPan, sanitizedTilt;
|
||||
|
||||
if (pan >= 1 && pan <= 18) {
|
||||
sanitizedPan = ("0" + pan).slice(-2);
|
||||
} else {
|
||||
throw 'The pan speed value must be greater than or equal to 1 and less than or equal to 18';
|
||||
}
|
||||
|
||||
if (tilt >= 1 && tilt <= 14) {
|
||||
sanitizedTilt = ("0" + pan).slice(-2);
|
||||
} else {
|
||||
throw 'The tilt speed value must be greater than or equal to 1 and less than or equal to 14';
|
||||
}
|
||||
|
||||
return [sanitizedPan, sanitizedTilt];
|
||||
}
|
||||
|
||||
async function getCurrentPos(id) {
|
||||
return numToHexStr(await socket.sendCmd(id, "81090612FF"));
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*jshint esversion: 6 */
|
||||
|
||||
const path = require('path');
|
||||
const db = require(path.resolve(__dirname, '../_helpers/db.js'));
|
||||
const Camera = db.Camera;
|
||||
const net = require('net');
|
||||
|
||||
module.exports = {
|
||||
sendCmd: _sendCmd
|
||||
};
|
||||
|
||||
async function _sendCmd(id, cmd) {
|
||||
const camera = await Camera.findById(id);
|
||||
const buffer = Buffer.from(cmd, 'hex');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const socket = new net.Socket({allowHalfOpen: true});
|
||||
const conn = net.createConnection(Number(camera.port), camera.ip);
|
||||
conn.setNoDelay();
|
||||
conn.setEncoding('hex');
|
||||
|
||||
conn.on('connect', () => {
|
||||
conn.write(buffer);
|
||||
});
|
||||
|
||||
conn.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
conn.on('data', (buf) => {
|
||||
if (conn.bytesRead >= 3) {
|
||||
conn.end();
|
||||
decode(buf.toString('hex'))
|
||||
.then((res) => {
|
||||
resolve(res);
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
reject("Unusual Camera Response: " + buf.toString('hex') + " connection bytes Read: " + conn.bytesRead);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function decode(hexStr) {
|
||||
let decoded = '';
|
||||
switch (hexStr) {
|
||||
case "9041ff":
|
||||
case "9042ff":
|
||||
decoded = "Command Accepted";
|
||||
break;
|
||||
case "9051ff":
|
||||
case "9041ff9051ff":
|
||||
decoded = "Socket1 Cmd Done";
|
||||
break;
|
||||
case "9052ff":
|
||||
case "9042ff9052ff":
|
||||
decoded = "Socket2 Cmd Done";
|
||||
break;
|
||||
case "906002ff":
|
||||
throw "Command Syntax Error";
|
||||
case "906003ff":
|
||||
throw "Command Buffer Full";
|
||||
case "906104ff":
|
||||
throw "Socket1 Cmd Cancelled";
|
||||
case "906204ff":
|
||||
throw "Socket2 Cmd Cancelled";
|
||||
case "906105ff":
|
||||
case "906205ff":
|
||||
throw "No Socket";
|
||||
case "906141ff":
|
||||
throw "Socket1 Cmd Not Executable";
|
||||
case "906241ff":
|
||||
throw "Socket2 Cmd Not Executable";
|
||||
default:
|
||||
throw "Unusual Camera Response: " + hexStr;
|
||||
}
|
||||
return decoded;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*jshint esversion: 6 */
|
||||
const path = require('path');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const cameraService = require(path.resolve(__dirname, './camera.service'));
|
||||
|
||||
router.post('/create', _create);
|
||||
router.get('/cameras', getAll);
|
||||
router.get('/', getById);
|
||||
router.put('/', update);
|
||||
router.delete('/', _delete);
|
||||
router.post('/osd', _osd);
|
||||
router.post('/stream', _stream);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
function _create(req, res, next) {
|
||||
cameraService.create(req.body)
|
||||
.then((camera) => res.json(camera))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function update(req, res, next) {
|
||||
cameraService.update(req.body.id)
|
||||
.then((camera) => res.json(camera))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function getAll(req, res, next) {
|
||||
cameraService.getAll()
|
||||
.then((cameras) => res.json(cameras))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function getById(req, res, next) {
|
||||
cameraService.getById(req.body.id)
|
||||
.then((camera) => res.json(camera))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _delete(req, res, next) {
|
||||
cameraService.delete(req.body.id)
|
||||
.then((id) => res.json(id))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _osd(req, res, next) {
|
||||
cameraService.osd(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _stream(req, res, next) {
|
||||
console.log("Stream Requester ip: " + req.ip);
|
||||
cameraService.stream(req.body)
|
||||
.then((streamPort) => res.json(streamPort))
|
||||
.catch(err => next(err));
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*jshint esversion: 6 */
|
||||
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const schema = new Schema({
|
||||
_id: Schema.Types.ObjectId,
|
||||
ip: {type: String, unique: true, required: true},
|
||||
port: {type: String, required: true},
|
||||
rtsp: {type: String, required: true},
|
||||
model: {type: String, required: true},
|
||||
serial: {type: String, required: true},
|
||||
name: {type: String, unique: true},
|
||||
streamPort: {type: Number, unique: true},
|
||||
presets: [
|
||||
{
|
||||
memNum: {type: Number, max: 127},
|
||||
name: {type: String},
|
||||
location: {
|
||||
pan: {type: String},
|
||||
tilt: {type: String},
|
||||
focus: {type: String},
|
||||
zoom: {type: String}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
schema.set('toJson', {virtuals: true});
|
||||
module.exports = mongoose.model('Camera', schema);
|
|
@ -0,0 +1,127 @@
|
|||
/*jshint esversion: 6 */
|
||||
const path = require('path');
|
||||
const Stream = require('../stream/videoStream');
|
||||
const db = require(path.resolve(__dirname, '../_helpers/db.js'));
|
||||
const mongoose = require('mongoose');
|
||||
const cameraHelper = require(path.resolve(__dirname, '../_helpers/cameraHelper.js'));
|
||||
const socket = require(path.resolve(__dirname, '../_helpers/socket.js'));
|
||||
const Camera = db.Camera;
|
||||
|
||||
module.exports = {
|
||||
create: _create,
|
||||
getAll: _getAll,
|
||||
getById: _getById,
|
||||
update: _update,
|
||||
delete: _delete,
|
||||
osd: _osd,
|
||||
stream: _stream
|
||||
};
|
||||
|
||||
async function _getAll() {
|
||||
try {
|
||||
return await Camera.find().lean();
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _getById(id) {
|
||||
try {
|
||||
return await Camera.findById(id).lean();
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _create(cameraParams) {
|
||||
if (await Camera.findOne({ip: cameraParams.ip})) {
|
||||
throw 'There is already a camera with ip ' + cameraParams.ip;
|
||||
} else {
|
||||
const modelSerialArr = await cameraHelper.getDeviceModel(cameraParams.ip);
|
||||
const camId = new mongoose.Types.ObjectId();
|
||||
const streamPort = await cameraHelper.createNewCameraStreamPort();
|
||||
return new Camera({
|
||||
...cameraParams,
|
||||
_id: camId,
|
||||
model: modelSerialArr[0],
|
||||
serial: modelSerialArr[1],
|
||||
streamPort: streamPort
|
||||
})
|
||||
.save()
|
||||
.then((camera) => {
|
||||
return camera.toObject();
|
||||
}).catch((err) => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function _update(cameraParams) {
|
||||
try {
|
||||
return await Camera.findByIdAndUpdate(cameraParams._id, cameraParams, {new: true}).save();
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _delete(id) {
|
||||
try {
|
||||
return await Camera.findOneAndDelete(id);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _osd({id, option}) {
|
||||
let osdHex = "8101";
|
||||
switch(option.toLowerCase()) {
|
||||
case "openToggle":
|
||||
osdHex += "043F025FFF";
|
||||
break;
|
||||
case "up":
|
||||
osdHex += "06010E0E0301FF";
|
||||
break;
|
||||
case "down":
|
||||
osdHex += "06010E0E0302FF";
|
||||
break;
|
||||
case "left":
|
||||
osdHex += "06010E0E0103FF";
|
||||
break;
|
||||
case "right":
|
||||
osdHex += "06010E0E0203FF";
|
||||
break;
|
||||
case "enter":
|
||||
osdHex += "060605FF";
|
||||
break;
|
||||
case "return":
|
||||
osdHex += "060604FF";
|
||||
break;
|
||||
default:
|
||||
throw "The OSD option " + option + " is not a recognizable OSD option.";
|
||||
}
|
||||
return await socket.sendCmd(id, osdHex);
|
||||
}
|
||||
|
||||
async function _stream({id, width = 1920, height = 1080}) {
|
||||
const camera = await Camera.findById(id).lean();
|
||||
|
||||
// In case a seperate user wants to reach same camera stream
|
||||
let inUse;
|
||||
try {
|
||||
inUse = await cameraHelper.checkPortUse(camera.streamPort);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!inUse) {
|
||||
const stream = new Stream({
|
||||
name: camera.name || "stream: " + camera.rtsp,
|
||||
url: 'rtsp://' + camera.rtsp,
|
||||
port: camera.streamPort,
|
||||
width: width,
|
||||
height: height
|
||||
});
|
||||
stream.start();
|
||||
}
|
||||
return camera.streamPort;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"connectionString": "mongodb://your-mongo-address/db-name",
|
||||
"secret": "your db-secret"
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/*jshint esversion: 6 */
|
||||
const path = require('path');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const imageService = require(path.resolve(__dirname, './image.service.js'));
|
||||
module.exports = router;
|
||||
|
||||
router.post('/bright', _brightness);
|
||||
router.post('/contrast', _contrast);
|
||||
router.post('/wb', _whiteBalance);
|
||||
router.post('/rgain', _rgain);
|
||||
router.post('/bgain', _bgain);
|
||||
router.post('/shutter', _shutter);
|
||||
router.post('/iris', _iris);
|
||||
router.post('/gain', _gain);
|
||||
router.post('/backLight', _backLight);
|
||||
router.post('/bw', _blackWhite);
|
||||
router.post('/flicker', _flicker);
|
||||
router.post('/imgFlip', _imgFlip);
|
||||
router.post('/colorHue', _colorHue);
|
||||
router.post('/ae', _autoExp);
|
||||
router.post('/save', _save);
|
||||
|
||||
function _brightness(req, res, next) {
|
||||
imageService.brightness(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _contrast(req, res, next) {
|
||||
imageService.contrast(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _whiteBalance(req, res, next) {
|
||||
imageService.whiteBalance(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _rgain(req, res, next) {
|
||||
imageService.rgain(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _bgain(req, res, next) {
|
||||
imageService.bgain(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _shutter(req, res, next) {
|
||||
imageService.shutter(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _iris(req, res, next) {
|
||||
imageService.iris(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _gain(req, res, next) {
|
||||
imageService.gain(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _backLight(req, res, next) {
|
||||
imageService.backLight(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _blackWhite(req, res, next) {
|
||||
imageService.blackWhite(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _flicker(req, res, next) {
|
||||
imageService.flicker(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _imgFlip(req, res, next) {
|
||||
imageService.imgFlip(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _colorHue(req, res, next) {
|
||||
imageService.colorHue(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _autoExp(req, res, next) {
|
||||
imageService.ae(req.body)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _save(req, res, next) {
|
||||
imageService.save(req.body.id)
|
||||
.then((socket) => res.json(socket))
|
||||
.catch(err => next(err));
|
||||
}
|
|
@ -0,0 +1,479 @@
|
|||
/*jshint esversion: 6 */
|
||||
const path = require('path');
|
||||
const db = require(path.resolve(__dirname, '../_helpers/db.js'));
|
||||
const ptzHelper = require(path.resolve(__dirname, '../_helpers/ptzHelper.js'));
|
||||
const socket = require(path.resolve(__dirname, '../_helpers/socket.js'));
|
||||
const Camera = db.Camera;
|
||||
|
||||
module.exports = {
|
||||
brightness: _brightness,
|
||||
contrast: _contrast,
|
||||
whiteBalance: whiteBal,
|
||||
rgain: _rgain,
|
||||
bgain: _bgain,
|
||||
shutter: _shutter,
|
||||
iris: _iris,
|
||||
gain: _gain,
|
||||
backLight: _backLight,
|
||||
blackWhite: _blackWhite,
|
||||
flicker: _flicker,
|
||||
imgFlip: _imgFlip,
|
||||
colorHue: _colorHue,
|
||||
ae: _autoExp,
|
||||
save: saveSetting
|
||||
};
|
||||
|
||||
async function _brightness({id, pos}) {
|
||||
let brightnessHex = "810104A10000";
|
||||
let brightnessPos = ptzHelper.numToHexStr(pos).padStart(4, "0");
|
||||
brightnessHex += brightnessPos + "FF";
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, brightnessHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _contrast(contrastParams) {
|
||||
const {id, pos} = contrastParams;
|
||||
let contrastHex = "810104A20000";
|
||||
let contrastPos = ptzHelper.numToHexStr(pos).padStart(4, "0");
|
||||
contrastHex += contrastPos + 'FF';
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, contrastHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function whiteBal({id, option, mode}) {
|
||||
let wbHex = "810104";
|
||||
|
||||
if (mode.toLowerCase() === 'wbmode') {
|
||||
switch(option.toLowerCase()) {
|
||||
case "auto":
|
||||
wbHex += "3500FF";
|
||||
break;
|
||||
case "indoor":
|
||||
wbHex += "3501FF";
|
||||
break;
|
||||
case "outdoor":
|
||||
wbHex += "3502FF";
|
||||
break;
|
||||
case "onepush":
|
||||
wbHex += "3503FF";
|
||||
break;
|
||||
case "manual":
|
||||
wbHex += "3505FF";
|
||||
break;
|
||||
case "onepush-trigger":
|
||||
wbHex += "1005FF";
|
||||
break;
|
||||
default:
|
||||
throw "The white balance mode " + option + " is not a recognizable white balance mode.";
|
||||
}
|
||||
} else if (mode.toLowerCase() === 'awbsenstivity') {
|
||||
switch(option.toLowerCase()) {
|
||||
case "high":
|
||||
wbHex += "A900FF";
|
||||
break;
|
||||
case "normal":
|
||||
wbHex += "A901FF";
|
||||
break;
|
||||
case "low":
|
||||
wbHex += "A902FF";
|
||||
break;
|
||||
default:
|
||||
throw "The auto white balance mode " + option + " is not a recognizable auto white balance mode.";
|
||||
}
|
||||
} else {
|
||||
throw mode + "is not a recognizable white balance method.";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, wbHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function _rgain({id, mode, option = null, pos = null}) {
|
||||
let rgainHex = "810104";
|
||||
|
||||
if (mode.toLowerCase() === 'standard') {
|
||||
switch (option.toLowerCase()) {
|
||||
case "reset":
|
||||
rgainHex += "0300FF";
|
||||
break;
|
||||
case "up":
|
||||
rgainHex += "0302FF";
|
||||
break;
|
||||
case "down":
|
||||
rgainHex += "0303FF";
|
||||
break;
|
||||
default:
|
||||
throw "The rgain option " + option + " is not a recognizable standard rgain option";
|
||||
}
|
||||
} else if (mode.toLowerCase() === 'direct') {
|
||||
rgainHex = "430000" + ptzHelper.numToHexStr(pos).padStart(4, "0") + "FF";
|
||||
} else {
|
||||
throw "The rgain mode " + mode + " is not a recognizable rgain method.";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, rgainHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _bgain({id, mode, option = null, pos = null}) {
|
||||
let bgainHex = "810104";
|
||||
|
||||
if (mode.toLowerCase() === 'standard') {
|
||||
switch (option.toLowerCase()) {
|
||||
case "reset":
|
||||
bgainHex += "0400FF";
|
||||
break;
|
||||
case "up":
|
||||
bgainHex += "0402FF";
|
||||
break;
|
||||
case "down":
|
||||
bgainHex += "0403FF";
|
||||
break;
|
||||
default:
|
||||
throw "The bgain option " + option + " is not a recognizable standard bgain option";
|
||||
}
|
||||
} else if (mode.toLowerCase() === 'direct') {
|
||||
rgainHex = "430000" + ptzHelper.numToHexStr(pos).padStart(4, "0") + "FF";
|
||||
} else {
|
||||
throw "The bgain mode " + mode + " is not a recognizable bgain method.";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, bgainHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _shutter({id, option, mode}) {
|
||||
let shutterHex = "8101040A";
|
||||
if (mode.toLowerCase() === 'standard') {
|
||||
switch (option.toLowerCase()) {
|
||||
case "reset":
|
||||
shutterHex += "00FF";
|
||||
break;
|
||||
case "up":
|
||||
shutterHex += "02FF";
|
||||
break;
|
||||
case "down":
|
||||
shutterHex += "03FF";
|
||||
break;
|
||||
default:
|
||||
throw "The shutter option " + option + " is not a recognizable standard shutter option";
|
||||
}
|
||||
} else if (mode.toLowerCase() === 'direct') {
|
||||
shutterHex += "0000";
|
||||
switch (option) {
|
||||
case "1/30":
|
||||
shutterHex += "0001FF";
|
||||
break;
|
||||
case "1/60":
|
||||
shutterHex += "0002FF";
|
||||
break;
|
||||
case "1/90":
|
||||
shutterHex += "0003FF";
|
||||
break;
|
||||
case "1/100":
|
||||
shutterHex += "0004FF";
|
||||
break;
|
||||
case "1/125":
|
||||
shutterHex += "0005FF";
|
||||
break;
|
||||
case "1/180":
|
||||
shutterHex += "0006FF";
|
||||
break;
|
||||
case "1/250":
|
||||
shutterHex += "0007FF";
|
||||
break;
|
||||
case "1/350":
|
||||
shutterHex += "0008FF";
|
||||
break;
|
||||
case "1/500":
|
||||
shutterHex += "0009FF";
|
||||
break;
|
||||
case "1/725":
|
||||
shutterHex += "000AFF";
|
||||
break;
|
||||
case "1/1000":
|
||||
shutterHex += "000BFF";
|
||||
break;
|
||||
case "1/1500":
|
||||
shutterHex += "000CFF";
|
||||
break;
|
||||
case "1/2000":
|
||||
shutterHex += "000DFF";
|
||||
break;
|
||||
case "1/3000":
|
||||
shutterHex += "000EFF";
|
||||
break;
|
||||
case "1/4000":
|
||||
shutterHex += "000FFF";
|
||||
break;
|
||||
case "1/6000":
|
||||
shutterHex += "0100FF";
|
||||
break;
|
||||
case "1/10000":
|
||||
shutterHex += "0101FF";
|
||||
break;
|
||||
default:
|
||||
throw "The shutter option " + option + " is not a recognizable direct shutter option";
|
||||
}
|
||||
} else {
|
||||
throw "The shutter mode " + mode + " is not a recognizable shutter mode";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, shutterHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
console.log("reached end");
|
||||
}
|
||||
|
||||
async function _iris({id, mode, option}) {
|
||||
let irisHex = "8101040B";
|
||||
|
||||
if (mode.toLowerCase() === 'standard') {
|
||||
switch (option.toLowerCase()) {
|
||||
case "reset":
|
||||
irisHex += "00FF";
|
||||
break;
|
||||
case "up":
|
||||
irisHex += "02FF";
|
||||
break;
|
||||
case "down":
|
||||
irisHex += "03FF";
|
||||
break;
|
||||
default:
|
||||
throw "The iris option " + option + " is not a recognizable standard iris option";
|
||||
}
|
||||
} else if (mode.toLowerCase() === 'direct') {
|
||||
irisHex += "0000";
|
||||
switch (option.toLowerCase()) {
|
||||
case "close":
|
||||
irisHex += "0000FF";
|
||||
break;
|
||||
case "f11":
|
||||
irisHex += "0006FF";
|
||||
break;
|
||||
case "f9.6":
|
||||
irisHex += "0007FF";
|
||||
break;
|
||||
case "f8.0":
|
||||
irisHex += "0008FF";
|
||||
break;
|
||||
case "f6.8":
|
||||
irisHex += "0009FF";
|
||||
break;
|
||||
case "f5.6":
|
||||
irisHex += "000AFF";
|
||||
break;
|
||||
case "f4.8":
|
||||
irisHex += "000BFF";
|
||||
break;
|
||||
case "f4.0":
|
||||
irisHex += "000CFF";
|
||||
break;
|
||||
case "f3.4":
|
||||
irisHex += "000DFF";
|
||||
break;
|
||||
case "f2.8":
|
||||
irisHex += "000EFF";
|
||||
break;
|
||||
case "f2.0":
|
||||
irisHex += "0100FF";
|
||||
break;
|
||||
case "f1.8":
|
||||
irisHex += "0200FF";
|
||||
break;
|
||||
default:
|
||||
throw "The iris direct option " + option + " is not a recognizable option";
|
||||
}
|
||||
} else {
|
||||
throw "The iris option " + option + " is not a recognizable direct iris option";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, irisHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _gain({id, mode, option = null, pos = null}) {
|
||||
let gainHex = "8101040C";
|
||||
if (mode.toLowerCase() === "standard") {
|
||||
switch(option.toLowerCase()) {
|
||||
case "reset":
|
||||
gainHex += "00FF";
|
||||
break;
|
||||
case "up":
|
||||
gainHex += "02FF";
|
||||
break;
|
||||
case "down":
|
||||
gainHex += "03FF";
|
||||
break;
|
||||
default:
|
||||
throw "The gain option " + option + " is not a recognizable standard gain option";
|
||||
}
|
||||
} else if (mode === "direct") {
|
||||
gainHex += "0000" + ptzHelper.numToHexStr(pos).padStart(4, "0") + "FF";
|
||||
} else {
|
||||
throw "The gain mode " + mode + " is not a recognizable gain mode";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, gainHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _backLight({id, option}) {
|
||||
let backlightHex = "81010433";
|
||||
if (option.toLowerCase() === 'on') {
|
||||
backlightHex += "02FF";
|
||||
} else if (option.toLowerCase() === 'off') {
|
||||
backlightHex += "03FF";
|
||||
} else {
|
||||
throw "The back light option " + option + " is not a recognizable back light option";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, backlightHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _blackWhite({id, option}) {
|
||||
let bwHex = "81010463";
|
||||
|
||||
if (option.toLowerCase() === 'on') {
|
||||
bwHex += "04FF";
|
||||
} else if (option.toLowerCase() === 'off') {
|
||||
bwHex += "00FF";
|
||||
} else {
|
||||
throw "The back light option " + option + " is not a recognizable back light option";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, bwHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _flicker({id, option}) {
|
||||
let flickerHex = "810104230";
|
||||
switch(option.toLowerCase()) {
|
||||
case "off":
|
||||
flickerHex += "0FF";
|
||||
break;
|
||||
case "50hz":
|
||||
flickerHex += "1FF";
|
||||
break;
|
||||
case "60hz":
|
||||
flickerHex += "2FF";
|
||||
break;
|
||||
default:
|
||||
throw "The flicker option " + option + " is not a recognizable standard flicker option";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, flickerHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _imgFlip({id, mode, option}) {
|
||||
let imgFlipHex = "810104";
|
||||
|
||||
if (mode.toLowerCase() === 'lr') {
|
||||
imgFlipHex += '61';
|
||||
} else if (mode.toLowerCase() === 'pf') {
|
||||
imgFlipHex += '66';
|
||||
} else {
|
||||
throw "The image flip mode " + mode + " is not a recognizable image flip mode";
|
||||
}
|
||||
|
||||
if (option.toLowerCase() === 'off') {
|
||||
imgFlipHex += '03FF';
|
||||
} else if (option.toLowerCase() === 'on') {
|
||||
imgFlipHex += '02FF';
|
||||
} else {
|
||||
throw "The image flip option " + option + " is not a recognizable image flip option";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, imgFlipHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _colorHue({id, pos}) {
|
||||
let colorHueHex = '8101044F';
|
||||
let colorHuePos = ptzHelper.numToHexStr(pos).padStart(8, "0");
|
||||
colorHueHex += colorHuePos + "FF";
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, colorHueHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _autoExp({id, option}) {
|
||||
let aeHex = '81010439';
|
||||
|
||||
switch (option.toLowerCase()) {
|
||||
case "fullauto":
|
||||
aeHex += '00FF';
|
||||
break;
|
||||
case "manual":
|
||||
aeHex += '03FF';
|
||||
break;
|
||||
case "shutter":
|
||||
aeHex += '0AFF';
|
||||
break;
|
||||
case "iris":
|
||||
aeHex += '0BFF';
|
||||
break;
|
||||
case "bright":
|
||||
aeHex += '0DFF';
|
||||
break;
|
||||
default:
|
||||
throw "The autoexp option " + option + " is not a recognizable autoexp option";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, aeHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSetting(id) {
|
||||
try {
|
||||
return await socket.sendCmd(id, "81010604FF");
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*jshint esversion: 6 */
|
||||
const path = require('path');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const ptzService = require(path.resolve(__dirname, './ptz.service.js'));
|
||||
|
||||
module.exports = router;
|
||||
|
||||
router.post('/motion', _motion);
|
||||
router.post('/presets', _presets);
|
||||
router.post('/focus', _focus);
|
||||
router.post('/zoom', _zoom);
|
||||
|
||||
function _presets(req, res, next) {
|
||||
ptzService.preset(req.body)
|
||||
.then((response) => res.send(response))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _motion(req, res, next) {
|
||||
ptzService.motion(req.body)
|
||||
.then((response) => res.send(response))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _focus(req, res, next) {
|
||||
ptzService.focus(req.body)
|
||||
.then((response) => res.send(response))
|
||||
.catch(err => next(err));
|
||||
}
|
||||
|
||||
function _zoom(req, res, next) {
|
||||
ptzService.zoom(req.body)
|
||||
.then((response) => res.send(response))
|
||||
.catch(err => next(err));
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/*jshint esversion: 6 */
|
||||
const path = require('path');
|
||||
const db = require(path.resolve(__dirname, '../_helpers/db.js'));
|
||||
const ptzHelper = require(path.resolve(__dirname, '../_helpers/ptzHelper.js'));
|
||||
const socket = require(path.resolve(__dirname, '../_helpers/socket.js'));
|
||||
const Camera = db.Camera;
|
||||
|
||||
module.exports = {
|
||||
preset: _presets,
|
||||
motion: _motion,
|
||||
focus: _focus,
|
||||
zoom: _zoom
|
||||
};
|
||||
|
||||
async function _presets({id, mode, speed = null, memNum = null}) {
|
||||
let memCmd;
|
||||
|
||||
switch(mode.toLowerCase()) {
|
||||
case 'speed':
|
||||
const recallSpeed = ptzHelper.numToHexStr(speed).padStart(2, "0");
|
||||
memCmd = "81010601" + recallSpeed + "FF";
|
||||
break;
|
||||
case 'call':
|
||||
memCmd = "8101043F02" + ptzHelper.numToHexStr(memNum).padStart(2, "0") + "FF";
|
||||
break;
|
||||
case 'set':
|
||||
memCmd = "8101043F01" + ptzHelper.numToHexStr(memNum).padStart(2, "0") + "FF";
|
||||
break;
|
||||
case 'reset':
|
||||
memCmd = "8101043F00" + ptzHelper.numToHexStr(memNum).padStart(2, "0") + "FF";
|
||||
break;
|
||||
default:
|
||||
throw "The preset mode " + mode + " is not a recognizable preset method.";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, memCmd);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _motion({id, mode, pan = null, tilt = null, panSpeed = null, tiltSpeed = null, direction = null}) {
|
||||
if (mode === 'absolute' || mode === 'relative' || mode === 'standard') {
|
||||
panTiltSpeedArr = ptzHelper.sanitizeSpeed(panSpeed, tiltSpeed);
|
||||
if (mode === 'absolute' || mode === 'relative') {
|
||||
pan = ptzHelper.numToHexStr(pan);
|
||||
tilt = ptzHelper.numToHexStr(tilt);
|
||||
}
|
||||
}
|
||||
|
||||
let motionHex;
|
||||
switch(mode.toLowerCase()) {
|
||||
case 'home':
|
||||
motionHex = "81010604FF";
|
||||
break;
|
||||
case 'absolute':
|
||||
motionHex = "81010602" + panTiltSpeedArr[0] + panTiltSpeedArr[1] + pan + tilt +"FF";
|
||||
break;
|
||||
case 'relative':
|
||||
motionHex = "81010603" + panTiltSpeedArr[0] + panTiltSpeedArr[1] + pan + tilt +"FF";
|
||||
break;
|
||||
case 'standard':
|
||||
motionHex = "81010601" + panTiltSpeedArr[0] + panTiltSpeedArr[1] + ptzHelper.translateDirection(direction);
|
||||
break;
|
||||
case 'current':
|
||||
motionHex = "81090612FF";
|
||||
break;
|
||||
default:
|
||||
throw "The option " + mode + " is not a recognizable motion method.";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, motionHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _focus({id, mode, option = null, focusPos = null, intensity = null}) {
|
||||
let focusHex = '';
|
||||
switch(mode.toLowerCase()) {
|
||||
case 'standard':
|
||||
focusHex = "81010408";
|
||||
|
||||
if (option === 'stop') {
|
||||
focusHex += "00FF";
|
||||
} else if (option === 'tele') {
|
||||
focusHex += "03FF";
|
||||
} else if (option === 'wide') {
|
||||
focusHex += "02FF";
|
||||
} else {
|
||||
throw "The focus option " + option + " is not a recognizable standard focus option";
|
||||
}
|
||||
break;
|
||||
case 'variable':
|
||||
focusHex = "81010408";
|
||||
if (option === 'tele') {
|
||||
focusHex += '3' + intensity + "FF";
|
||||
} else if (option === 'wide') {
|
||||
focusHex += '2' + intensity + "FF";
|
||||
} else {
|
||||
throw "The focus option " + option + " is not a recognizable variable focus option";
|
||||
}
|
||||
break;
|
||||
case 'direct':
|
||||
focusPos = numToHexStr(focusPos).split('').reduce((str, char) => {
|
||||
return '0' + char;
|
||||
});
|
||||
focusPos = focusPos.padStart(8, "0");
|
||||
focusHex = "81010448" + focusPos + "FF";
|
||||
break;
|
||||
case 'focusmode':
|
||||
focusHex = "810";
|
||||
if (option === 'auto') {
|
||||
focusHex += "1043802FF";
|
||||
} else if (option === 'manual') {
|
||||
focusHex += "1043803FF";
|
||||
} else if (option === 'toggle') {
|
||||
focusHex += "1043810FF";
|
||||
} else if (option === 'lock') {
|
||||
focusHex += "A046802FF";
|
||||
} else if (option === 'unlock') {
|
||||
focusHex += "A046803FF";
|
||||
} else {
|
||||
throw "The focus option " + option + " is not a recognizable focus mode option";
|
||||
}
|
||||
break;
|
||||
case 'afzone':
|
||||
focusHex = "810104AA";
|
||||
if (option === 'top') {
|
||||
focusHex += "00FF";
|
||||
} else if (option === 'center') {
|
||||
focusHex += "01FF";
|
||||
} else if (option === 'bottom') {
|
||||
focusHex += "02FF";
|
||||
} else {
|
||||
throw "The focus option " + option + " is not a recognizable auto focus-zone option";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw "The focus mode " + mode + " is not a recognizable focus method.";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, focusHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function _zoom({id, mode, option = null, zoomPos = null, intensity}) {
|
||||
let zoomHex = '';
|
||||
|
||||
switch (mode) {
|
||||
case 'standard':
|
||||
zoomHex = "81010407";
|
||||
if (option === "stop") {
|
||||
zoomHex += "00FF";
|
||||
} else if (option === "tele") {
|
||||
zoomHex += "02FF";
|
||||
} else if (option === 'wide') {
|
||||
zoomHex += "03FF";
|
||||
} else {
|
||||
throw "The zoom option " + option + " is not a recognizable standard zoom option";
|
||||
}
|
||||
break;
|
||||
case 'variable':
|
||||
zoomHex = "81010407";
|
||||
if (option === 'tele') {
|
||||
zoomHex += '2' + intensity + "FF";
|
||||
} else if (option === 'wide') {
|
||||
zoomHex += '3' + intensity + "FF";
|
||||
} else {
|
||||
throw "The zoom option " + option + " is not a recognizable variable zoom option";
|
||||
}
|
||||
break;
|
||||
case 'direct':
|
||||
zoomPos = numToHexStr(zoomPos).split('').reduce((str, char) => {
|
||||
return '0' + char;
|
||||
});
|
||||
zoomPos = zoomPos.padStart(8, "0");
|
||||
zoomHex = "81010447" + zoomPos + "FF";
|
||||
break;
|
||||
default:
|
||||
throw "The zoom mode " + mode + " is not a recognizable zoom method.";
|
||||
}
|
||||
|
||||
try {
|
||||
return await socket.sendCmd(id, zoomHex);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*jshint esversion: 6 */
|
||||
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;
|
||||
const child_process = require('child_process');
|
||||
const EventEmitter = require('events');
|
||||
const spawn = require('cross-spawn');
|
||||
|
||||
class Mpeg1Muxer extends EventEmitter {
|
||||
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.url = options.url;
|
||||
this.width = options.width;
|
||||
// this.stream = child_process.spawn(ffmpegPath, ['-y', '-loglevel', 'quiet', "-rtsp_transport", "tcp", "-i", this.url, '-vf', 'yadif', '-f', 'mpegts', '-r', '30', '-codec:v', 'mpeg1video', '-codec:a', 'mp2', '-b:a', '128k', '-b:v', '4096k', '-muxdelay', '0', '-', './app/stream/stream.ts'], {
|
||||
// detached: false
|
||||
// });
|
||||
this.stream = child_process.spawn(ffmpegPath, ['-y', '-loglevel', 'quiet', "-rtsp_transport", "tcp", "-i", this.url, '-filter:v', 'scale=1280:-1', '-f', 'mpegts', '-r', '30', '-codec:v', 'mpeg1video', '-codec:a', 'mp2', '-b:a', '128k', '-b:v', '1500k', '-', './app/stream/stream.ts'], {
|
||||
detached: false
|
||||
});
|
||||
|
||||
this.inputStreamStarted = true;
|
||||
this.stream.stdout.on('data', (data) => { return this.emit('mpeg1data', data); });
|
||||
this.stream.stderr.on('data', (data) => { return this.emit('ffmpegError', data); });
|
||||
}
|
||||
|
||||
stop() {
|
||||
try {
|
||||
this.stream.stdout.removeAllListeners();
|
||||
} catch(err) {
|
||||
console |