From 93b5e9d7c68ae63065df4956f0f2024fc2ea4032 Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Sun, 7 Aug 2016 10:05:18 +0200 Subject: [PATCH] Added error handling to FFmpeg (to prevent process shutdown) Files are now written to a '.recording' file first and moved afterwards --- .gitignore | 3 ++- index.js | 2 +- processor-ffmpeg.js | 29 ++++++++++++++++++++++++----- processor-http-ffmpeg.js | 28 ++++++++++++++++++++++------ processor-http-raw.js | 12 ++++++++++-- 5 files changed, 59 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 3e4d1b2..7705c20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /config.js /node_modules/ -*.sublime-workspace \ No newline at end of file +*.sublime-workspace +ipcam_cgi_sdk.pdf \ No newline at end of file diff --git a/index.js b/index.js index df21b8a..07c8915 100644 --- a/index.js +++ b/index.js @@ -51,7 +51,7 @@ app.get('/capture/:camId', function(req, res) if (config.cams.hasOwnProperty(camId)) { - capture.start(config.cams[camId], moment()); + capture.start(camId, config.cams[camId], moment()); console.log('Started capture for: ' + camId); res.send(JSON.stringify([camId])); diff --git a/processor-ffmpeg.js b/processor-ffmpeg.js index 44cec76..9905f53 100644 --- a/processor-ffmpeg.js +++ b/processor-ffmpeg.js @@ -20,6 +20,22 @@ util.inherits(FFMPEGProcessor, BaseProcessor); FFMPEGProcessor.prototype.run = function() { var self = this; + var filename = helpers.createVariableFilename(this.cam.options.filename, this.now, + { + camId: this.camId + }); + + var tempFilename = filename + '.recording'; + var cleanup = function() + { + fs.rename(tempFilename, filename, function(err) + { + console.log('Error: could not move ' + tempFilename + ' to ' + filename + ': ' + err.message); + self.doEnd(); + }); + } + + var command = new FfmpegCommand(); command .input(this.cam.options.input) @@ -33,16 +49,19 @@ FFMPEGProcessor.prototype.run = function() } command - .output(helpers.createVariableFilename(this.cam.options.filename, this.now, - { - camId: this.camId - })) + .output(tempFilename) .videoCodec(this.cam.options.videoCodec) .outputFormat(this.cam.options.outputFormat); + command.on('error', function(err, stdout, stderr) + { + console.log('Error: FFmpeg output:' + err.message); + cleanup(); + }); + command.on('end', function() { - self.doEnd(); + cleanup(); }); self.doStart(); diff --git a/processor-http-ffmpeg.js b/processor-http-ffmpeg.js index 82dfc95..183854d 100644 --- a/processor-http-ffmpeg.js +++ b/processor-http-ffmpeg.js @@ -20,6 +20,14 @@ util.inherits(HTTPFFMPEGProcessor, BaseHTTPStreamProcessor); HTTPFFMPEGProcessor.prototype.run = function() { this.output = new stream.PassThrough(); + this.filename = helpers.createVariableFilename(this.cam.options.filename, this.now, + { + camId: this.camId + }); + + this.tempFilename = filename + '.recording'; + + var command = new FfmpegCommand(); command .input(this.output) @@ -29,13 +37,16 @@ HTTPFFMPEGProcessor.prototype.run = function() command.inputOption('-use_wallclock_as_timestamps 1'); command - .output(helpers.createVariableFilename(this.cam.options.filename, this.now, - { - camId: this.camId - })) + .output(this.tempFilename) .videoCodec(this.cam.options.videoCodec) - .outputFormat(this.cam.options.outputFormat) - .run(); + .outputFormat(this.cam.options.outputFormat); + + command.on('error', function(err, stdout, stderr) + { + console.log('Error: FFmpeg output:' + err.message); + }); + + command.run(); HTTPFFMPEGProcessor.super_.prototype.run.call(this); } @@ -54,6 +65,11 @@ HTTPFFMPEGProcessor.prototype.cleanup = function() this.output.end(); this.output = null; } + + fs.rename(this.tempFilename, this.filename, function(err) + { + console.log('Error: could not move ' + this.tempFilename + ' to ' + this.filename + ': ' + err.message); + }); } module.exports = HTTPFFMPEGProcessor; \ No newline at end of file diff --git a/processor-http-raw.js b/processor-http-raw.js index a8e1713..05a6c21 100644 --- a/processor-http-raw.js +++ b/processor-http-raw.js @@ -15,10 +15,13 @@ util.inherits(HTTPRawProcessor, BaseHTTPStreamProcessor); HTTPRawProcessor.prototype.run = function() { - this.output = fs.createWriteStream(helpers.createVariableFilename(this.cam.options.filename, this.now, + this.filename = helpers.createVariableFilename(this.cam.options.filename, this.now, { camId: this.camId - })); + }); + + this.tempFilename = this.filename + '.recording'; + this.output = fs.createWriteStream(this.tempFilename); HTTPRawProcessor.super_.prototype.run.call(this); } @@ -41,6 +44,11 @@ HTTPRawProcessor.prototype.cleanup = function() this.output.end(); this.output = null; } + + fs.rename(this.tempFilename, this.filename, function(err) + { + console.log('Error: could not move ' + this.tempFilename + ' to ' + this.filename + ': ' + err.message); + }); } module.exports = HTTPRawProcessor; \ No newline at end of file