Skip to content

Commit

Permalink
Merge pull request fluent-ffmpeg#697 from rhodgkins/stream-errors
Browse files Browse the repository at this point in the history
Exposed stream errors to error event
  • Loading branch information
njoyard authored Apr 23, 2017
2 parents 3c293f5 + c6ea17e commit 9f492c3
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 6 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,8 @@ ffmpeg('/path/to/file.avi')

The `error` event is emitted when an error occurs when running ffmpeg or when preparing its execution. It is emitted with an error object as an argument. If the error happened during ffmpeg execution, listeners will also receive two additional arguments containing ffmpegs stdout and stderr.

If streams are used for input or output, any errors emitted from these streams will be passed through to this event, attached to the `error` as `inputStreamError` and `outputStreamError` for input and output streams respectively.

**Warning**: you should _always_ set a handler for the `error` event, as node's default behaviour when an `error` event without any listeners is emitted is to output the error to the console and _terminate the program_.

```js
Expand Down
16 changes: 10 additions & 6 deletions lib/processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ module.exports = function(proto) {
* Emitted when an error happens when preparing or running a command
*
* @event FfmpegCommand#error
* @param {Error} error error object
* @param {Error} error error object, with optional properties 'inputStreamError' / 'outputStreamError' for errors on their respective streams
* @param {String|null} stdout ffmpeg stdout, unless outputting to a stream
* @param {String|null} stderr ffmpeg stderr
*/
Expand Down Expand Up @@ -444,7 +444,9 @@ module.exports = function(proto) {
// Pipe input stream if any
if (inputStream) {
inputStream.source.on('error', function(err) {
emitEnd(new Error('Input stream error: ' + err.message));
var reportingErr = new Error('Input stream error: ' + err.message);
reportingErr.inputStreamError = err;
emitEnd(reportingErr);
ffmpegProc.kill();
});

Expand Down Expand Up @@ -474,7 +476,7 @@ module.exports = function(proto) {

// Handle output stream events
outputStream.target.on('close', function() {
self.logger.debug('Output stream closed, scheduling kill for ffmpgeg process');
self.logger.debug('Output stream closed, scheduling kill for ffmpeg process');

// Don't kill process yet, to give a chance to ffmpeg to
// terminate successfully first This is necessary because
Expand All @@ -487,9 +489,11 @@ module.exports = function(proto) {
});

outputStream.target.on('error', function(err) {
self.logger.debug('Output stream error, killing ffmpgeg process');
emitEnd(new Error('Output stream error: ' + err.message), stdoutRing.get(), stderrRing.get());
ffmpegProc.kill();
self.logger.debug('Output stream error, killing ffmpeg process');
var reportingErr = new Error('Output stream error: ' + err.message);
reportingErr.outputStreamError = err;
emitEnd(reportingErr, stdoutRing.get(), stderrRing.get());
ffmpegProc.kill('SIGKILL');
});
}

Expand Down
80 changes: 80 additions & 0 deletions test/processor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,48 @@ describe('Processor', function() {
})
.saveToFile(testFile);
});

it('should pass input stream errors through to error handler', function(done) {
var testFile = path.join(__dirname, 'assets', 'testConvertFromStream.avi')

const readError = new Error('Read Error')
const instream = new (require('stream').Readable)({
read() {
process.nextTick(() => this.emit('error', readError))
}
})

const command = this.getCommand({ source: instream, logger: testhelper.logger })

let startCalled = false
const self = this

command
.usingPreset('divx')
.on('start', function() {
startCalled = true
command.ffmpegProc.on('exit', function() {
fs.exists(testFile, (exists) => {
exists.should.be.false()
done()
})
})
})
.on('error', function(err, stdout, stderr) {
self.saveOutput(stdout, stderr)
startCalled.should.be.true()
assert.ok(err)
err.message.indexOf('Input stream error: ').should.equal(0)
assert.strictEqual(err.inputStreamError, readError)
})
.on('end', function(stdout, stderr) {
testhelper.logOutput(stdout, stderr)
console.log('end was called, expected a error')
assert.ok(false)
done()
})
.saveToFile(testFile)
})
});

describe('mergeToFile', function() {
Expand Down Expand Up @@ -911,6 +953,44 @@ describe('Processor', function() {
new FfmpegCommand().writeToStream({end: true});
}).should.throw(/PassThrough stream is not supported on node v0.8/);
});

it('should pass output stream errors through to error handler', function(done) {

const writeError = new Error('Write Error')
const outstream = new (require('stream').Writable)({
write(chunk, encoding, callback) {
callback(writeError)
}
})

const command = this.getCommand({ source: this.testfile, logger: testhelper.logger })

let startCalled = false
const self = this

command
.usingPreset('divx')
.on('start', function() {
startCalled = true
command.ffmpegProc.on('exit', function() {
done()
})
})
.on('error', function(err, stdout, stderr) {
self.saveOutput(stdout, stderr)
startCalled.should.be.true()
assert.ok(err)
err.message.indexOf('Output stream error: ').should.equal(0)
assert.strictEqual(err.outputStreamError, writeError)
})
.on('end', function(stdout, stderr) {
console.log('end was called, expected a error')
testhelper.logOutput(stdout, stderr)
assert.ok(false)
done()
})
.writeToStream(outstream)
})
});

describe('Outputs', function() {
Expand Down

0 comments on commit 9f492c3

Please sign in to comment.