-
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Drop inherits dependency, convert to ES class
Convert to ES class in order to drop the `inherits` dependency. This is not a breaking change since the exposed interface is still the same, i.e. ```js var stream = mp4.decode() ``` and ```js var stream = mp4.encode() ```
- Loading branch information
Showing
5 changed files
with
2,113 additions
and
255 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,190 +1,183 @@ | ||
var stream = require('readable-stream') | ||
var inherits = require('inherits') | ||
var nextEvent = require('next-event') | ||
var Box = require('mp4-box-encoding') | ||
|
||
var EMPTY = Buffer.alloc(0) | ||
|
||
module.exports = Decoder | ||
class Decoder extends stream.Writable { | ||
constructor (opts) { | ||
super(opts) | ||
|
||
function Decoder () { | ||
if (!(this instanceof Decoder)) return new Decoder() | ||
stream.Writable.call(this) | ||
this.destroyed = false | ||
|
||
this.destroyed = false | ||
this._pending = 0 | ||
this._missing = 0 | ||
this._ignoreEmpty = false | ||
this._buf = null | ||
this._str = null | ||
this._cb = null | ||
this._ondrain = null | ||
this._writeBuffer = null | ||
this._writeCb = null | ||
|
||
this._pending = 0 | ||
this._missing = 0 | ||
this._ignoreEmpty = false | ||
this._buf = null | ||
this._str = null | ||
this._cb = null | ||
this._ondrain = null | ||
this._writeBuffer = null | ||
this._writeCb = null | ||
this._ondrain = null | ||
this._kick() | ||
} | ||
|
||
this._ondrain = null | ||
this._kick() | ||
} | ||
destroy (err) { | ||
if (this.destroyed) return | ||
this.destroyed = true | ||
if (err) this.emit('error', err) | ||
this.emit('close') | ||
} | ||
|
||
inherits(Decoder, stream.Writable) | ||
_write (data, enc, next) { | ||
if (this.destroyed) return | ||
var drained = !this._str || !this._str._writableState.needDrain | ||
|
||
Decoder.prototype.destroy = function (err) { | ||
if (this.destroyed) return | ||
this.destroyed = true | ||
if (err) this.emit('error', err) | ||
this.emit('close') | ||
} | ||
while (data.length && !this.destroyed) { | ||
if (!this._missing && !this._ignoreEmpty) { | ||
this._writeBuffer = data | ||
this._writeCb = next | ||
return | ||
} | ||
|
||
Decoder.prototype._write = function (data, enc, next) { | ||
if (this.destroyed) return | ||
var drained = !this._str || !this._str._writableState.needDrain | ||
var consumed = data.length < this._missing ? data.length : this._missing | ||
if (this._buf) data.copy(this._buf, this._buf.length - this._missing) | ||
else if (this._str) drained = this._str.write(consumed === data.length ? data : data.slice(0, consumed)) | ||
|
||
while (data.length && !this.destroyed) { | ||
if (!this._missing && !this._ignoreEmpty) { | ||
this._writeBuffer = data | ||
this._writeCb = next | ||
return | ||
} | ||
this._missing -= consumed | ||
|
||
var consumed = data.length < this._missing ? data.length : this._missing | ||
if (this._buf) data.copy(this._buf, this._buf.length - this._missing) | ||
else if (this._str) drained = this._str.write(consumed === data.length ? data : data.slice(0, consumed)) | ||
if (!this._missing) { | ||
var buf = this._buf | ||
var cb = this._cb | ||
var stream = this._str | ||
|
||
this._missing -= consumed | ||
this._buf = this._cb = this._str = this._ondrain = null | ||
drained = true | ||
|
||
if (!this._missing) { | ||
var buf = this._buf | ||
var cb = this._cb | ||
var stream = this._str | ||
this._ignoreEmpty = false | ||
if (stream) stream.end() | ||
if (cb) cb(buf) | ||
} | ||
|
||
this._buf = this._cb = this._str = this._ondrain = null | ||
drained = true | ||
data = consumed === data.length ? EMPTY : data.slice(consumed) | ||
} | ||
|
||
this._ignoreEmpty = false | ||
if (stream) stream.end() | ||
if (cb) cb(buf) | ||
if (this._pending && !this._missing) { | ||
this._writeBuffer = data | ||
this._writeCb = next | ||
return | ||
} | ||
|
||
data = consumed === data.length ? EMPTY : data.slice(consumed) | ||
if (drained) next() | ||
else this._ondrain(next) | ||
} | ||
|
||
if (this._pending && !this._missing) { | ||
this._writeBuffer = data | ||
this._writeCb = next | ||
return | ||
_buffer (size, cb) { | ||
this._missing = size | ||
this._buf = Buffer.alloc(size) | ||
this._cb = cb | ||
} | ||
|
||
if (drained) next() | ||
else this._ondrain(next) | ||
} | ||
_stream (size, cb) { | ||
this._missing = size | ||
this._str = new MediaData(this) | ||
this._ondrain = nextEvent(this._str, 'drain') | ||
this._pending++ | ||
this._str.on('end', () => { | ||
this._pending-- | ||
this._kick() | ||
}) | ||
this._cb = cb | ||
return this._str | ||
} | ||
|
||
Decoder.prototype._buffer = function (size, cb) { | ||
this._missing = size | ||
this._buf = Buffer.alloc(size) | ||
this._cb = cb | ||
} | ||
_readBox () { | ||
const bufferHeaders = (len, buf) => { | ||
this._buffer(len, additionalBuf => { | ||
if (buf) { | ||
buf = Buffer.concat([buf, additionalBuf]) | ||
} else { | ||
buf = additionalBuf | ||
} | ||
var headers = Box.readHeaders(buf) | ||
if (typeof headers === 'number') { | ||
bufferHeaders(headers - buf.length, buf) | ||
} else { | ||
this._pending++ | ||
this._headers = headers | ||
this.emit('box', headers) | ||
} | ||
}) | ||
} | ||
|
||
Decoder.prototype._stream = function (size, cb) { | ||
var self = this | ||
this._missing = size | ||
this._str = new MediaData(this) | ||
this._ondrain = nextEvent(this._str, 'drain') | ||
this._pending++ | ||
this._str.on('end', function () { | ||
self._pending-- | ||
self._kick() | ||
}) | ||
this._cb = cb | ||
return this._str | ||
} | ||
bufferHeaders(8) | ||
} | ||
|
||
Decoder.prototype._readBox = function () { | ||
var self = this | ||
bufferHeaders(8) | ||
stream () { | ||
if (!this._headers) throw new Error('this function can only be called once after \'box\' is emitted') | ||
var headers = this._headers | ||
this._headers = null | ||
|
||
function bufferHeaders (len, buf) { | ||
self._buffer(len, function (additionalBuf) { | ||
if (buf) { | ||
buf = Buffer.concat([buf, additionalBuf]) | ||
} else { | ||
buf = additionalBuf | ||
} | ||
var headers = Box.readHeaders(buf) | ||
if (typeof headers === 'number') { | ||
bufferHeaders(headers - buf.length, buf) | ||
} else { | ||
self._pending++ | ||
self._headers = headers | ||
self.emit('box', headers) | ||
} | ||
}) | ||
return this._stream(headers.contentLen, null) | ||
} | ||
} | ||
|
||
Decoder.prototype.stream = function () { | ||
var self = this | ||
if (!self._headers) throw new Error('this function can only be called once after \'box\' is emitted') | ||
var headers = self._headers | ||
self._headers = null | ||
decode (cb) { | ||
if (!this._headers) throw new Error('this function can only be called once after \'box\' is emitted') | ||
var headers = this._headers | ||
this._headers = null | ||
|
||
return self._stream(headers.contentLen, null) | ||
} | ||
|
||
Decoder.prototype.decode = function (cb) { | ||
var self = this | ||
if (!self._headers) throw new Error('this function can only be called once after \'box\' is emitted') | ||
var headers = self._headers | ||
self._headers = null | ||
|
||
self._buffer(headers.contentLen, function (buf) { | ||
var box = Box.decodeWithoutHeaders(headers, buf) | ||
cb(box) | ||
self._pending-- | ||
self._kick() | ||
}) | ||
} | ||
this._buffer(headers.contentLen, buf => { | ||
var box = Box.decodeWithoutHeaders(headers, buf) | ||
cb(box) | ||
this._pending-- | ||
this._kick() | ||
}) | ||
} | ||
|
||
Decoder.prototype.ignore = function () { | ||
var self = this | ||
if (!self._headers) throw new Error('this function can only be called once after \'box\' is emitted') | ||
var headers = self._headers | ||
self._headers = null | ||
ignore () { | ||
if (!this._headers) throw new Error('this function can only be called once after \'box\' is emitted') | ||
var headers = this._headers | ||
this._headers = null | ||
|
||
this._missing = headers.contentLen | ||
if (this._missing === 0) { | ||
this._ignoreEmpty = true | ||
this._missing = headers.contentLen | ||
if (this._missing === 0) { | ||
this._ignoreEmpty = true | ||
} | ||
this._cb = () => { | ||
this._pending-- | ||
this._kick() | ||
} | ||
} | ||
this._cb = function () { | ||
self._pending-- | ||
self._kick() | ||
|
||
_kick () { | ||
if (this._pending) return | ||
if (!this._buf && !this._str) this._readBox() | ||
if (this._writeBuffer) { | ||
var next = this._writeCb | ||
var buffer = this._writeBuffer | ||
this._writeBuffer = null | ||
this._writeCb = null | ||
this._write(buffer, null, next) | ||
} | ||
} | ||
} | ||
|
||
Decoder.prototype._kick = function () { | ||
if (this._pending) return | ||
if (!this._buf && !this._str) this._readBox() | ||
if (this._writeBuffer) { | ||
var next = this._writeCb | ||
var buffer = this._writeBuffer | ||
this._writeBuffer = null | ||
this._writeCb = null | ||
this._write(buffer, null, next) | ||
class MediaData extends stream.PassThrough { | ||
constructor (parent) { | ||
super() | ||
this._parent = parent | ||
this.destroyed = false | ||
} | ||
} | ||
|
||
function MediaData (parent) { | ||
this._parent = parent | ||
this.destroyed = false | ||
stream.PassThrough.call(this) | ||
destroy (err) { | ||
if (this.destroyed) return | ||
this.destroyed = true | ||
this._parent.destroy(err) | ||
if (err) this.emit('error', err) | ||
this.emit('close') | ||
} | ||
} | ||
|
||
inherits(MediaData, stream.PassThrough) | ||
|
||
MediaData.prototype.destroy = function (err) { | ||
if (this.destroyed) return | ||
this.destroyed = true | ||
this._parent.destroy(err) | ||
if (err) this.emit('error', err) | ||
this.emit('close') | ||
} | ||
module.exports = Decoder |
Oops, something went wrong.