diff options
| author | 8cy <[email protected]> | 2020-04-03 02:37:42 -0700 |
|---|---|---|
| committer | 8cy <[email protected]> | 2020-04-03 02:37:42 -0700 |
| commit | 60867fb030bae582082340ead7dbc7efdc2f5398 (patch) | |
| tree | 4c6a7356351be2e4914e15c4703172597c45656e /node_modules/prism-media/src | |
| parent | commenting (diff) | |
| download | s5nical-60867fb030bae582082340ead7dbc7efdc2f5398.tar.xz s5nical-60867fb030bae582082340ead7dbc7efdc2f5398.zip | |
2020/04/03, 02:34, v1.2.0
Diffstat (limited to 'node_modules/prism-media/src')
| -rw-r--r-- | node_modules/prism-media/src/Prism.js | 17 | ||||
| -rw-r--r-- | node_modules/prism-media/src/index.js | 6 | ||||
| -rw-r--r-- | node_modules/prism-media/src/opus/OggOpus.js | 90 | ||||
| -rw-r--r-- | node_modules/prism-media/src/transcoders/MediaTranscoder.js | 31 | ||||
| -rw-r--r-- | node_modules/prism-media/src/transcoders/ffmpeg/Ffmpeg.js | 56 | ||||
| -rw-r--r-- | node_modules/prism-media/src/transcoders/ffmpeg/FfmpegProcess.js | 95 | ||||
| -rw-r--r-- | node_modules/prism-media/src/util/Constants.js | 0 |
7 files changed, 295 insertions, 0 deletions
diff --git a/node_modules/prism-media/src/Prism.js b/node_modules/prism-media/src/Prism.js new file mode 100644 index 0000000..b2cee9e --- /dev/null +++ b/node_modules/prism-media/src/Prism.js @@ -0,0 +1,17 @@ +const MediaTranscoder = require('./transcoders/MediaTranscoder'); + +class Prism { + constructor() { + this.transcoder = new MediaTranscoder(this); + } + + createTranscoder(...args) { + return this.transcode(...args); + } + + transcode(...args) { + return this.transcoder.transcode(...args); + } +} + +module.exports = Prism; diff --git a/node_modules/prism-media/src/index.js b/node_modules/prism-media/src/index.js new file mode 100644 index 0000000..9437f57 --- /dev/null +++ b/node_modules/prism-media/src/index.js @@ -0,0 +1,6 @@ +const Prism = require('./Prism'); +const MediaTranscoder = require('./transcoders/MediaTranscoder'); + +Prism.MediaTranscoder = MediaTranscoder; + +module.exports = Prism; diff --git a/node_modules/prism-media/src/opus/OggOpus.js b/node_modules/prism-media/src/opus/OggOpus.js new file mode 100644 index 0000000..9a938cd --- /dev/null +++ b/node_modules/prism-media/src/opus/OggOpus.js @@ -0,0 +1,90 @@ +const { Transform } = require('stream'); + +const OGG_PAGE_HEADER_SIZE = 26; +const STREAM_STRUCTURE_VERSION = 0; + +const OGGS_HEADER = Buffer.from('OggS'.split('').map(x => x.charCodeAt(0))); +const OPUS_HEAD = Buffer.from('OpusHead'.split('').map(x => x.charCodeAt(0))); +const OPUS_TAGS = Buffer.from('OpusTags'.split('').map(x => x.charCodeAt(0))); + +class OggOpusTransform extends Transform { + constructor() { + super(); + this._remainder = null; + this._head = null; + } + + _transform(chunk, encoding, done) { + if (this._remainder) { + chunk = Buffer.concat([this._remainder, chunk]); + this._remainder = null; + } + + while (chunk) { + try { + const result = this.readPage(chunk); + if (result) chunk = result; + else break; + } catch (err) { + this.emit('error', err); + } + } + this._remainder = chunk; + done(); + } + + /** + * Reads a page from a buffer + * @param {Buffer} chunk The chunk containing the page + * @returns {boolean|Buffer} + */ + readPage(chunk) { + if (chunk.length < OGG_PAGE_HEADER_SIZE) { + return false; + } + if (!chunk.slice(0, 4).equals(OGGS_HEADER)) { + throw Error(`capture_pattern is not ${OGGS_HEADER}`); + } + if (chunk.readUInt8(4) !== STREAM_STRUCTURE_VERSION) { + throw Error(`stream_structure_version is not ${STREAM_STRUCTURE_VERSION}`); + } + + const pageSegments = chunk.readUInt8(26), + table = chunk.slice(27, 27 + pageSegments); + + let sizes = [], totalSize = 0; + + for (let i = 0; i < pageSegments;) { + let size = 0, x = 255; + while (x === 255) { + x = table.readUInt8(i); + i++; + size += x; + } + sizes.push(size); + totalSize += size; + } + + if (chunk.length < 27 + pageSegments + totalSize) { + return false; + } + + let start = 27 + pageSegments; + for (const size of sizes) { + const segment = chunk.slice(start, start + size); + const header = segment.slice(0, 8); + if (this._head) { + if (header.equals(OPUS_TAGS)) this.emit('opusTags', segment); + else this.push(segment); + } else if (header.equals(OPUS_HEAD)) { + this._head = segment; + } else { + throw Error(`Invalid segment ${segment}`); + } + start += size; + } + return chunk.slice(start); + } +} + +module.exports = OggOpusTransform; diff --git a/node_modules/prism-media/src/transcoders/MediaTranscoder.js b/node_modules/prism-media/src/transcoders/MediaTranscoder.js new file mode 100644 index 0000000..217e34c --- /dev/null +++ b/node_modules/prism-media/src/transcoders/MediaTranscoder.js @@ -0,0 +1,31 @@ +const Ffmpeg = require('./ffmpeg/Ffmpeg'); + +const transcoders = [ + 'ffmpeg', +]; + +class MediaTranscoder { + constructor(prism) { + this.prism = prism; + this.ffmpeg = new Ffmpeg(this); + } + + static verifyOptions(options) { + if (!options) throw new Error('Options must be passed to MediaTranscoder.transcode()'); + if (!options.type) throw new Error('Options.type must be passed to MediaTranscoder.transcode()'); + if (!transcoders.includes(options.type)) throw new Error(`Options.type must be: ${transcoders.join(' ')}`); + return options; + } + + /** + * Transcodes a media stream based on specified options + * @param {Object} options the options to use when transcoding + * @returns {ReadableStream} the transcodeed stream + */ + transcode(options) { + options = MediaTranscoder.verifyOptions(options); + return this[options.type].transcode(options); + } +} + +module.exports = MediaTranscoder; diff --git a/node_modules/prism-media/src/transcoders/ffmpeg/Ffmpeg.js b/node_modules/prism-media/src/transcoders/ffmpeg/Ffmpeg.js new file mode 100644 index 0000000..b34dadc --- /dev/null +++ b/node_modules/prism-media/src/transcoders/ffmpeg/Ffmpeg.js @@ -0,0 +1,56 @@ +const ChildProcess = require('child_process'); +const FfmpegProcess = require('./FfmpegProcess'); + +class FfmpegTranscoder { + constructor(mediaTranscoder) { + this.mediaTranscoder = mediaTranscoder; + this.command = FfmpegTranscoder.selectFfmpegCommand(); + this.processes = []; + } + + static verifyOptions(options) { + if (!options) throw new Error('Options not provided!'); + if (!options.media) throw new Error('Media must be provided'); + if (!options.ffmpegArguments || !(options.ffmpegArguments instanceof Array)) { + throw new Error('FFMPEG Arguments must be an array'); + } + if (options.ffmpegArguments.includes('-i')) return options; + if (typeof options.media === 'string') { + options.ffmpegArguments = ['-i', `${options.media}`].concat(options.ffmpegArguments).concat(['pipe:1']); + } else { + options.ffmpegArguments = ['-i', '-'].concat(options.ffmpegArguments).concat(['pipe:1']); + } + return options; + } + + /** + * Transcodes an input using FFMPEG + * @param {FfmpegTranscoderOptions} options the options to use + * @returns {FfmpegProcess} the created FFMPEG process + * @throws {FFMPEGOptionsError} + */ + transcode(options) { + if (!this.command) this.command = FfmpegTranscoder.selectFfmpegCommand(); + const proc = new FfmpegProcess(this, FfmpegTranscoder.verifyOptions(options)); + this.processes.push(proc); + return proc; + } + + static selectFfmpegCommand() { + try { + const ffmpegStatic = require('ffmpeg-static'); + return ffmpegStatic.path || ffmpegStatic; + } catch (err1) { + try { + return require('ffmpeg-binaries'); + } catch (err2) { + for (const command of ['ffmpeg', 'avconv', './ffmpeg', './avconv']) { + if (!ChildProcess.spawnSync(command, ['-h']).error) return command; + } + throw new Error('FFMPEG not found'); + } + } + } +} + +module.exports = FfmpegTranscoder; diff --git a/node_modules/prism-media/src/transcoders/ffmpeg/FfmpegProcess.js b/node_modules/prism-media/src/transcoders/ffmpeg/FfmpegProcess.js new file mode 100644 index 0000000..c6561a9 --- /dev/null +++ b/node_modules/prism-media/src/transcoders/ffmpeg/FfmpegProcess.js @@ -0,0 +1,95 @@ +const EventEmitter = require('events').EventEmitter; +const ChildProcess = require('child_process'); + +/** + * A spawned FFMPEG process + */ +class FfmpegProcess extends EventEmitter { + constructor(ffmpegTranscoder, options) { + super(); + /** + * The ffmpeg process + * @type {ChildProcess} + */ + this.process = ChildProcess.spawn(ffmpegTranscoder.command, options.ffmpegArguments); + /** + * The FFMPEG transcoder that created this process + * @type {FfmpegTranscoder} + */ + this.transcoder = ffmpegTranscoder; + /** + * The input media + * @type {?ReadableStream|string} + */ + this.inputMedia = options.media; + + if (typeof this.inputMedia !== 'string') { + try { + this.connectStream(this.inputMedia); + } catch (e) { + this.emit('error', e, 'instantiation'); + } + } else { + this.attachErrorHandlers(); + } + + this.on('error', this.kill.bind(this)); + this.once('end', this.kill.bind(this)); + } + + /** + * The ffmpeg output stream + * @type {?ReadableStream} + */ + get output() { + return this.process ? this.process.stdout : null; + } + + attachErrorHandlers() { + this.process.stdin.on('error', e => { + // if not killed + if (this.process) { + this.emit('error', e, 'ffmpegProcess.stdin'); + } + }); + this.process.stdout.on('error', e => { + // if not killed + if (this.process) { + this.emit('error', e, 'ffmpegProcess.stdout'); + } + }); + this.process.on('error', e => this.emit('error', e, 'ffmpegProcess')); + this.process.stdout.on('end', () => this.emit('end')); + } + + /** + * Connects an input stream to the ffmpeg process + * @param {ReadableStream} inputMedia the stream to pass to ffmpeg + * @returns {ReadableStream} the ffmpeg output stream + */ + connectStream(inputMedia) { + if (!this.process) throw new Error('No FFMPEG process available'); + this.inputMedia = inputMedia; + this.inputMedia.pipe(this.process.stdin, { end: false }); + + inputMedia.on('error', e => this.emit('error', e, 'inputstream', inputMedia)); + + this.attachErrorHandlers(); + + return this.process.stdout; + } + + /** + * Kills the ffmpeg process + */ + kill() { + if (!this.process) return; + if (this.inputMedia && this.inputMedia.unpipe) { + this.inputMedia.unpipe(this.process.stdin); + } + this.process.kill('SIGKILL'); + this.process = null; + } +} + +module.exports = FfmpegProcess; diff --git a/node_modules/prism-media/src/util/Constants.js b/node_modules/prism-media/src/util/Constants.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/node_modules/prism-media/src/util/Constants.js |