diff --git a/web-service/package.json b/web-service/package.json index 384597f3461e64b2041471258661b826d198ae1d..973ba267987e4bbc96c8839f6fa057db1f6ad181 100644 --- a/web-service/package.json +++ b/web-service/package.json @@ -16,6 +16,7 @@ "license": "ISC", "dependencies": { "body-parser": "^1.19.0", + "event-emitter": "^0.3.5", "express": "^4.16.4", "express-ws": "^4.0.0", "mongoose": "^5.7.3", diff --git a/web-service/public/js/bundle.js b/web-service/public/js/bundle.js index 312f7bc60f8010ff54ee0db73f8afdbbe4d1aba0..5e809d92752710afa1b85276dc7abe9505614101 100644 --- a/web-service/public/js/bundle.js +++ b/web-service/public/js/bundle.js @@ -508,7 +508,7 @@ var objectKeys = Object.keys || function (obj) { }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"object-assign":62,"util/":4}],2:[function(require,module,exports){ +},{"object-assign":78,"util/":4}],2:[function(require,module,exports){ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { @@ -1669,7 +1669,7 @@ BufferList.prototype._match = function(offset, search) { module.exports = BufferList -},{"readable-stream":72,"safe-buffer":74,"util":81}],7:[function(require,module,exports){ +},{"readable-stream":88,"safe-buffer":90,"util":102}],7:[function(require,module,exports){ },{}],8:[function(require,module,exports){ // shim for using process in browser @@ -3638,7 +3638,7 @@ function numberIsNaN (obj) { } }).call(this,require("buffer").Buffer) -},{"base64-js":5,"buffer":9,"ieee754":12}],10:[function(require,module,exports){ +},{"base64-js":5,"buffer":9,"ieee754":28}],10:[function(require,module,exports){ (function (Buffer){ // Copyright Joyent, Inc. and other Node contributors. // @@ -3749,7 +3749,349 @@ function objectToString(o) { } }).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":14}],11:[function(require,module,exports){ +},{"../../is-buffer/index.js":30}],11:[function(require,module,exports){ +"use strict"; + +var isValue = require("type/value/is") + , isPlainFunction = require("type/plain-function/is") + , assign = require("es5-ext/object/assign") + , normalizeOpts = require("es5-ext/object/normalize-options") + , contains = require("es5-ext/string/#/contains"); + +var d = (module.exports = function (dscr, value/*, options*/) { + var c, e, w, options, desc; + if (arguments.length < 2 || typeof dscr !== "string") { + options = value; + value = dscr; + dscr = null; + } else { + options = arguments[2]; + } + if (isValue(dscr)) { + c = contains.call(dscr, "c"); + e = contains.call(dscr, "e"); + w = contains.call(dscr, "w"); + } else { + c = w = true; + e = false; + } + + desc = { value: value, configurable: c, enumerable: e, writable: w }; + return !options ? desc : assign(normalizeOpts(options), desc); +}); + +d.gs = function (dscr, get, set/*, options*/) { + var c, e, options, desc; + if (typeof dscr !== "string") { + options = set; + set = get; + get = dscr; + dscr = null; + } else { + options = arguments[3]; + } + if (!isValue(get)) { + get = undefined; + } else if (!isPlainFunction(get)) { + options = get; + get = set = undefined; + } else if (!isValue(set)) { + set = undefined; + } else if (!isPlainFunction(set)) { + options = set; + set = undefined; + } + if (isValue(dscr)) { + c = contains.call(dscr, "c"); + e = contains.call(dscr, "e"); + } else { + c = true; + e = false; + } + + desc = { get: get, set: set, configurable: c, enumerable: e }; + return !options ? desc : assign(normalizeOpts(options), desc); +}; + +},{"es5-ext/object/assign":13,"es5-ext/object/normalize-options":20,"es5-ext/string/#/contains":23,"type/plain-function/is":97,"type/value/is":99}],12:[function(require,module,exports){ +"use strict"; + +// eslint-disable-next-line no-empty-function +module.exports = function () {}; + +},{}],13:[function(require,module,exports){ +"use strict"; + +module.exports = require("./is-implemented")() ? Object.assign : require("./shim"); + +},{"./is-implemented":14,"./shim":15}],14:[function(require,module,exports){ +"use strict"; + +module.exports = function () { + var assign = Object.assign, obj; + if (typeof assign !== "function") return false; + obj = { foo: "raz" }; + assign(obj, { bar: "dwa" }, { trzy: "trzy" }); + return obj.foo + obj.bar + obj.trzy === "razdwatrzy"; +}; + +},{}],15:[function(require,module,exports){ +"use strict"; + +var keys = require("../keys") + , value = require("../valid-value") + , max = Math.max; + +module.exports = function (dest, src/*, …srcn*/) { + var error, i, length = max(arguments.length, 2), assign; + dest = Object(value(dest)); + assign = function (key) { + try { + dest[key] = src[key]; + } catch (e) { + if (!error) error = e; + } + }; + for (i = 1; i < length; ++i) { + src = arguments[i]; + keys(src).forEach(assign); + } + if (error !== undefined) throw error; + return dest; +}; + +},{"../keys":17,"../valid-value":22}],16:[function(require,module,exports){ +"use strict"; + +var _undefined = require("../function/noop")(); // Support ES3 engines + +module.exports = function (val) { return val !== _undefined && val !== null; }; + +},{"../function/noop":12}],17:[function(require,module,exports){ +"use strict"; + +module.exports = require("./is-implemented")() ? Object.keys : require("./shim"); + +},{"./is-implemented":18,"./shim":19}],18:[function(require,module,exports){ +"use strict"; + +module.exports = function () { + try { + Object.keys("primitive"); + return true; + } catch (e) { + return false; + } +}; + +},{}],19:[function(require,module,exports){ +"use strict"; + +var isValue = require("../is-value"); + +var keys = Object.keys; + +module.exports = function (object) { return keys(isValue(object) ? Object(object) : object); }; + +},{"../is-value":16}],20:[function(require,module,exports){ +"use strict"; + +var isValue = require("./is-value"); + +var forEach = Array.prototype.forEach, create = Object.create; + +var process = function (src, obj) { + var key; + for (key in src) obj[key] = src[key]; +}; + +// eslint-disable-next-line no-unused-vars +module.exports = function (opts1/*, …options*/) { + var result = create(null); + forEach.call(arguments, function (options) { + if (!isValue(options)) return; + process(Object(options), result); + }); + return result; +}; + +},{"./is-value":16}],21:[function(require,module,exports){ +"use strict"; + +module.exports = function (fn) { + if (typeof fn !== "function") throw new TypeError(fn + " is not a function"); + return fn; +}; + +},{}],22:[function(require,module,exports){ +"use strict"; + +var isValue = require("./is-value"); + +module.exports = function (value) { + if (!isValue(value)) throw new TypeError("Cannot use null or undefined"); + return value; +}; + +},{"./is-value":16}],23:[function(require,module,exports){ +"use strict"; + +module.exports = require("./is-implemented")() ? String.prototype.contains : require("./shim"); + +},{"./is-implemented":24,"./shim":25}],24:[function(require,module,exports){ +"use strict"; + +var str = "razdwatrzy"; + +module.exports = function () { + if (typeof str.contains !== "function") return false; + return str.contains("dwa") === true && str.contains("foo") === false; +}; + +},{}],25:[function(require,module,exports){ +"use strict"; + +var indexOf = String.prototype.indexOf; + +module.exports = function (searchString/*, position*/) { + return indexOf.call(this, searchString, arguments[1]) > -1; +}; + +},{}],26:[function(require,module,exports){ +'use strict'; + +var d = require('d') + , callable = require('es5-ext/object/valid-callable') + + , apply = Function.prototype.apply, call = Function.prototype.call + , create = Object.create, defineProperty = Object.defineProperty + , defineProperties = Object.defineProperties + , hasOwnProperty = Object.prototype.hasOwnProperty + , descriptor = { configurable: true, enumerable: false, writable: true } + + , on, once, off, emit, methods, descriptors, base; + +on = function (type, listener) { + var data; + + callable(listener); + + if (!hasOwnProperty.call(this, '__ee__')) { + data = descriptor.value = create(null); + defineProperty(this, '__ee__', descriptor); + descriptor.value = null; + } else { + data = this.__ee__; + } + if (!data[type]) data[type] = listener; + else if (typeof data[type] === 'object') data[type].push(listener); + else data[type] = [data[type], listener]; + + return this; +}; + +once = function (type, listener) { + var once, self; + + callable(listener); + self = this; + on.call(this, type, once = function () { + off.call(self, type, once); + apply.call(listener, this, arguments); + }); + + once.__eeOnceListener__ = listener; + return this; +}; + +off = function (type, listener) { + var data, listeners, candidate, i; + + callable(listener); + + if (!hasOwnProperty.call(this, '__ee__')) return this; + data = this.__ee__; + if (!data[type]) return this; + listeners = data[type]; + + if (typeof listeners === 'object') { + for (i = 0; (candidate = listeners[i]); ++i) { + if ((candidate === listener) || + (candidate.__eeOnceListener__ === listener)) { + if (listeners.length === 2) data[type] = listeners[i ? 0 : 1]; + else listeners.splice(i, 1); + } + } + } else { + if ((listeners === listener) || + (listeners.__eeOnceListener__ === listener)) { + delete data[type]; + } + } + + return this; +}; + +emit = function (type) { + var i, l, listener, listeners, args; + + if (!hasOwnProperty.call(this, '__ee__')) return; + listeners = this.__ee__[type]; + if (!listeners) return; + + if (typeof listeners === 'object') { + l = arguments.length; + args = new Array(l - 1); + for (i = 1; i < l; ++i) args[i - 1] = arguments[i]; + + listeners = listeners.slice(); + for (i = 0; (listener = listeners[i]); ++i) { + apply.call(listener, this, args); + } + } else { + switch (arguments.length) { + case 1: + call.call(listeners, this); + break; + case 2: + call.call(listeners, this, arguments[1]); + break; + case 3: + call.call(listeners, this, arguments[1], arguments[2]); + break; + default: + l = arguments.length; + args = new Array(l - 1); + for (i = 1; i < l; ++i) { + args[i - 1] = arguments[i]; + } + apply.call(listeners, this, args); + } + } +}; + +methods = { + on: on, + once: once, + off: off, + emit: emit +}; + +descriptors = { + on: d(on), + once: d(once), + off: d(off), + emit: d(emit) +}; + +base = defineProperties({}, descriptors); + +module.exports = exports = function (o) { + return (o == null) ? create(base) : defineProperties(Object(o), descriptors); +}; +exports.methods = methods; + +},{"d":11,"es5-ext/object/valid-callable":21}],27:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -4274,7 +4616,7 @@ function functionBindPolyfill(context) { }; } -},{}],12:[function(require,module,exports){ +},{}],28:[function(require,module,exports){ exports.read = function (buffer, offset, isLE, mLen, nBytes) { var e, m var eLen = (nBytes * 8) - mLen - 1 @@ -4360,9 +4702,9 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { buffer[offset + i - d] |= s * 128 } -},{}],13:[function(require,module,exports){ +},{}],29:[function(require,module,exports){ arguments[4][2][0].apply(exports,arguments) -},{"dup":2}],14:[function(require,module,exports){ +},{"dup":2}],30:[function(require,module,exports){ /*! * Determine if an object is a Buffer * @@ -4385,14 +4727,14 @@ function isSlowBuffer (obj) { return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) } -},{}],15:[function(require,module,exports){ +},{}],31:[function(require,module,exports){ var toString = {}.toString; module.exports = Array.isArray || function (arr) { return toString.call(arr) == '[object Array]'; }; -},{}],16:[function(require,module,exports){ +},{}],32:[function(require,module,exports){ 'use strict' var Buffer = require('safe-buffer').Buffer @@ -4479,7 +4821,7 @@ function msgpack (options) { module.exports = msgpack -},{"./lib/decoder":17,"./lib/encoder":18,"./lib/streams":19,"assert":1,"bl":6,"safe-buffer":74}],17:[function(require,module,exports){ +},{"./lib/decoder":33,"./lib/encoder":34,"./lib/streams":35,"assert":1,"bl":6,"safe-buffer":90}],33:[function(require,module,exports){ 'use strict' var bl = require('bl') @@ -4917,7 +5259,7 @@ module.exports = function buildDecode (decodingTypes) { module.exports.IncompleteBufferError = IncompleteBufferError -},{"bl":6,"util":81}],18:[function(require,module,exports){ +},{"bl":6,"util":102}],34:[function(require,module,exports){ 'use strict' var Buffer = require('safe-buffer').Buffer @@ -5262,7 +5604,7 @@ function encodeFloat (obj, forceFloat64) { return buf } -},{"bl":6,"safe-buffer":74}],19:[function(require,module,exports){ +},{"bl":6,"safe-buffer":90}],35:[function(require,module,exports){ 'use strict' var Transform = require('readable-stream').Transform @@ -5354,7 +5696,7 @@ Decoder.prototype._transform = function (buf, enc, done) { module.exports.decoder = Decoder module.exports.encoder = Encoder -},{"bl":6,"inherits":13,"readable-stream":72}],20:[function(require,module,exports){ +},{"bl":6,"inherits":29,"readable-stream":88}],36:[function(require,module,exports){ /** * mux.js * @@ -5487,7 +5829,7 @@ AacStream.prototype = new Stream(); module.exports = AacStream; -},{"../utils/stream.js":61,"./utils":21}],21:[function(require,module,exports){ +},{"../utils/stream.js":77,"./utils":37}],37:[function(require,module,exports){ /** * mux.js * @@ -5660,7 +6002,7 @@ module.exports = { parseAacTimestamp: parseAacTimestamp }; -},{}],22:[function(require,module,exports){ +},{}],38:[function(require,module,exports){ /** * mux.js * @@ -5818,7 +6160,7 @@ AdtsStream.prototype = new Stream(); module.exports = AdtsStream; -},{"../utils/clock":59,"../utils/stream.js":61}],23:[function(require,module,exports){ +},{"../utils/clock":75,"../utils/stream.js":77}],39:[function(require,module,exports){ /** * mux.js * @@ -6305,7 +6647,7 @@ module.exports = { NalByteStream: NalByteStream }; -},{"../utils/exp-golomb.js":60,"../utils/stream.js":61}],24:[function(require,module,exports){ +},{"../utils/exp-golomb.js":76,"../utils/stream.js":77}],40:[function(require,module,exports){ /** * mux.js * @@ -6317,7 +6659,7 @@ module.exports = { h264: require('./h264') }; -},{"./adts":22,"./h264":23}],25:[function(require,module,exports){ +},{"./adts":38,"./h264":39}],41:[function(require,module,exports){ // constants var AUDIO_PROPERTIES = [ 'audioobjecttype', @@ -6329,7 +6671,7 @@ var AUDIO_PROPERTIES = [ module.exports = AUDIO_PROPERTIES; -},{}],26:[function(require,module,exports){ +},{}],42:[function(require,module,exports){ var VIDEO_PROPERTIES = [ 'width', 'height', @@ -6342,7 +6684,7 @@ var VIDEO_PROPERTIES = [ module.exports = VIDEO_PROPERTIES; -},{}],27:[function(require,module,exports){ +},{}],43:[function(require,module,exports){ /** * mux.js * @@ -6392,7 +6734,7 @@ module.exports = function() { return silence; }; -},{}],28:[function(require,module,exports){ +},{}],44:[function(require,module,exports){ /** * mux.js * @@ -6545,7 +6887,7 @@ CoalesceStream.prototype.flush = function(flushSource) { module.exports = CoalesceStream; -},{"../utils/stream.js":61}],29:[function(require,module,exports){ +},{"../utils/stream.js":77}],45:[function(require,module,exports){ /** * mux.js * @@ -6613,7 +6955,7 @@ var getFlvHeader = function(duration, audio, video) { // :ByteArray { module.exports = getFlvHeader; -},{"./flv-tag.js":30}],30:[function(require,module,exports){ +},{"./flv-tag.js":46}],46:[function(require,module,exports){ /** * mux.js * @@ -6992,7 +7334,7 @@ FlvTag.frameTime = function(tag) { module.exports = FlvTag; -},{}],31:[function(require,module,exports){ +},{}],47:[function(require,module,exports){ /** * mux.js * @@ -7005,7 +7347,7 @@ module.exports = { getFlvHeader: require('./flv-header') }; -},{"./flv-header":29,"./flv-tag":30,"./transmuxer":33}],32:[function(require,module,exports){ +},{"./flv-header":45,"./flv-tag":46,"./transmuxer":49}],48:[function(require,module,exports){ /** * mux.js * @@ -7038,7 +7380,7 @@ var TagList = function() { module.exports = TagList; -},{}],33:[function(require,module,exports){ +},{}],49:[function(require,module,exports){ /** * mux.js * @@ -7493,7 +7835,7 @@ Transmuxer.prototype = new Stream(); // forward compatibility module.exports = Transmuxer; -},{"../codecs/adts.js":22,"../codecs/h264":23,"../m2ts/m2ts.js":37,"../utils/stream.js":61,"./coalesce-stream.js":28,"./flv-tag.js":30,"./tag-list.js":32}],34:[function(require,module,exports){ +},{"../codecs/adts.js":38,"../codecs/h264":39,"../m2ts/m2ts.js":53,"../utils/stream.js":77,"./coalesce-stream.js":44,"./flv-tag.js":46,"./tag-list.js":48}],50:[function(require,module,exports){ /** * mux.js * @@ -7518,7 +7860,7 @@ muxjs.mp2t.tools = require('./tools/ts-inspector'); module.exports = muxjs; -},{"./codecs":24,"./flv":31,"./m2ts":36,"./mp4":45,"./partial":51,"./tools/flv-inspector":55,"./tools/mp4-inspector":56,"./tools/ts-inspector":57}],35:[function(require,module,exports){ +},{"./codecs":40,"./flv":47,"./m2ts":52,"./mp4":61,"./partial":67,"./tools/flv-inspector":71,"./tools/mp4-inspector":72,"./tools/ts-inspector":73}],51:[function(require,module,exports){ /** * mux.js * @@ -8377,7 +8719,7 @@ module.exports = { Cea608Stream: Cea608Stream }; -},{"../tools/caption-packet-parser":54,"../utils/stream":61}],36:[function(require,module,exports){ +},{"../tools/caption-packet-parser":70,"../utils/stream":77}],52:[function(require,module,exports){ /** * mux.js * @@ -8386,7 +8728,7 @@ module.exports = { */ module.exports = require('./m2ts'); -},{"./m2ts":37}],37:[function(require,module,exports){ +},{"./m2ts":53}],53:[function(require,module,exports){ /** * mux.js * @@ -8926,7 +9268,7 @@ for (var type in StreamTypes) { module.exports = m2ts; -},{"../utils/stream.js":61,"./caption-stream":35,"./metadata-stream":38,"./stream-types":40,"./timestamp-rollover-stream":41}],38:[function(require,module,exports){ +},{"../utils/stream.js":77,"./caption-stream":51,"./metadata-stream":54,"./stream-types":56,"./timestamp-rollover-stream":57}],54:[function(require,module,exports){ /** * mux.js * @@ -9181,7 +9523,7 @@ MetadataStream.prototype = new Stream(); module.exports = MetadataStream; -},{"../utils/stream":61,"./stream-types":40}],39:[function(require,module,exports){ +},{"../utils/stream":77,"./stream-types":56}],55:[function(require,module,exports){ /** * mux.js * @@ -9470,7 +9812,7 @@ module.exports = { videoPacketContainsKeyFrame: videoPacketContainsKeyFrame }; -},{"./stream-types.js":40}],40:[function(require,module,exports){ +},{"./stream-types.js":56}],56:[function(require,module,exports){ /** * mux.js * @@ -9485,7 +9827,7 @@ module.exports = { METADATA_STREAM_TYPE: 0x15 }; -},{}],41:[function(require,module,exports){ +},{}],57:[function(require,module,exports){ /** * mux.js * @@ -9588,7 +9930,7 @@ module.exports = { handleRollover: handleRollover }; -},{"../utils/stream":61}],42:[function(require,module,exports){ +},{"../utils/stream":77}],58:[function(require,module,exports){ /** * mux.js * @@ -9745,7 +10087,7 @@ module.exports = { concatenateFrameData: concatenateFrameData }; -},{"../data/silence":27,"../utils/clock":59}],43:[function(require,module,exports){ +},{"../data/silence":43,"../utils/clock":75}],59:[function(require,module,exports){ /** * mux.js * @@ -10200,7 +10542,7 @@ var CaptionParser = function() { module.exports = CaptionParser; -},{"../m2ts/caption-stream":35,"../tools/caption-packet-parser":54,"../tools/mp4-inspector":56,"./probe":47}],44:[function(require,module,exports){ +},{"../m2ts/caption-stream":51,"../tools/caption-packet-parser":70,"../tools/mp4-inspector":72,"./probe":63}],60:[function(require,module,exports){ /** * mux.js * @@ -10521,7 +10863,7 @@ module.exports = { concatenateNalDataForFrame: concatenateNalDataForFrame }; -},{}],45:[function(require,module,exports){ +},{}],61:[function(require,module,exports){ /** * mux.js * @@ -10537,7 +10879,7 @@ module.exports = { CaptionParser: require('./caption-parser') }; -},{"./caption-parser":43,"./mp4-generator":46,"./probe":47,"./transmuxer":49}],46:[function(require,module,exports){ +},{"./caption-parser":59,"./mp4-generator":62,"./probe":63,"./transmuxer":65}],62:[function(require,module,exports){ /** * mux.js * @@ -11338,7 +11680,7 @@ module.exports = { } }; -},{}],47:[function(require,module,exports){ +},{}],63:[function(require,module,exports){ /** * mux.js * @@ -11689,7 +12031,7 @@ module.exports = { getTimescaleFromMediaHeader: getTimescaleFromMediaHeader }; -},{"../tools/mp4-inspector.js":56,"../utils/bin":58}],48:[function(require,module,exports){ +},{"../tools/mp4-inspector.js":72,"../utils/bin":74}],64:[function(require,module,exports){ /** * mux.js * @@ -11798,7 +12140,7 @@ module.exports = { collectDtsInfo: collectDtsInfo }; -},{"../utils/clock":59}],49:[function(require,module,exports){ +},{"../utils/clock":75}],65:[function(require,module,exports){ /** * mux.js * @@ -12982,7 +13324,7 @@ module.exports = { generateVideoSegmentTimingInfo: generateVideoSegmentTimingInfo }; -},{"../aac":20,"../aac/utils":21,"../codecs/adts.js":22,"../codecs/h264":23,"../constants/audio-properties.js":25,"../constants/video-properties.js":26,"../m2ts/m2ts.js":37,"../utils/clock":59,"../utils/stream.js":61,"./audio-frame-utils":42,"./frame-utils":44,"./mp4-generator.js":46,"./track-decode-info":48}],50:[function(require,module,exports){ +},{"../aac":36,"../aac/utils":37,"../codecs/adts.js":38,"../codecs/h264":39,"../constants/audio-properties.js":41,"../constants/video-properties.js":42,"../m2ts/m2ts.js":53,"../utils/clock":75,"../utils/stream.js":77,"./audio-frame-utils":58,"./frame-utils":60,"./mp4-generator.js":62,"./track-decode-info":64}],66:[function(require,module,exports){ 'use strict'; var Stream = require('../utils/stream.js'); @@ -13138,12 +13480,12 @@ AudioSegmentStream.prototype = new Stream(); module.exports = AudioSegmentStream; -},{"../constants/audio-properties.js":25,"../mp4/audio-frame-utils":42,"../mp4/mp4-generator.js":46,"../mp4/track-decode-info.js":48,"../utils/clock":59,"../utils/stream.js":61}],51:[function(require,module,exports){ +},{"../constants/audio-properties.js":41,"../mp4/audio-frame-utils":58,"../mp4/mp4-generator.js":62,"../mp4/track-decode-info.js":64,"../utils/clock":75,"../utils/stream.js":77}],67:[function(require,module,exports){ module.exports = { Transmuxer: require('./transmuxer') }; -},{"./transmuxer":52}],52:[function(require,module,exports){ +},{"./transmuxer":68}],68:[function(require,module,exports){ var Stream = require('../utils/stream.js'); var m2ts = require('../m2ts/m2ts.js'); var codecs = require('../codecs/index.js'); @@ -13523,7 +13865,7 @@ Transmuxer.prototype = new Stream(); module.exports = Transmuxer; -},{"../aac/index":20,"../aac/utils":21,"../codecs/adts":22,"../codecs/index.js":24,"../m2ts/m2ts.js":37,"../mp4/track-decode-info.js":48,"../utils/clock":59,"../utils/stream.js":61,"./audio-segment-stream.js":50,"./video-segment-stream.js":53}],53:[function(require,module,exports){ +},{"../aac/index":36,"../aac/utils":37,"../codecs/adts":38,"../codecs/index.js":40,"../m2ts/m2ts.js":53,"../mp4/track-decode-info.js":64,"../utils/clock":75,"../utils/stream.js":77,"./audio-segment-stream.js":66,"./video-segment-stream.js":69}],69:[function(require,module,exports){ /** * Constructs a single-track, ISO BMFF media segment from H264 data * events. The output of this stream can be fed to a SourceBuffer @@ -13733,7 +14075,7 @@ VideoSegmentStream.prototype = new Stream(); module.exports = VideoSegmentStream; -},{"../constants/video-properties.js":26,"../mp4/frame-utils":44,"../mp4/mp4-generator.js":46,"../mp4/track-decode-info.js":48,"../utils/stream.js":61}],54:[function(require,module,exports){ +},{"../constants/video-properties.js":42,"../mp4/frame-utils":60,"../mp4/mp4-generator.js":62,"../mp4/track-decode-info.js":64,"../utils/stream.js":77}],70:[function(require,module,exports){ /** * mux.js * @@ -13931,7 +14273,7 @@ module.exports = { USER_DATA_REGISTERED_ITU_T_T35: USER_DATA_REGISTERED_ITU_T_T35 }; -},{}],55:[function(require,module,exports){ +},{}],71:[function(require,module,exports){ /** * mux.js * @@ -14105,7 +14447,7 @@ module.exports = { textify: textifyFlv }; -},{}],56:[function(require,module,exports){ +},{}],72:[function(require,module,exports){ /** * mux.js * @@ -15008,7 +15350,7 @@ module.exports = { parseSidx: parse.sidx }; -},{"../utils/bin":58}],57:[function(require,module,exports){ +},{"../utils/bin":74}],73:[function(require,module,exports){ /** * mux.js * @@ -15531,7 +15873,7 @@ module.exports = { parseAudioPes_: parseAudioPes_ }; -},{"../aac/utils.js":21,"../m2ts/probe.js":39,"../m2ts/stream-types.js":40,"../m2ts/timestamp-rollover-stream.js":41,"../utils/clock":59}],58:[function(require,module,exports){ +},{"../aac/utils.js":37,"../m2ts/probe.js":55,"../m2ts/stream-types.js":56,"../m2ts/timestamp-rollover-stream.js":57,"../utils/clock":75}],74:[function(require,module,exports){ /** * mux.js * @@ -15551,7 +15893,7 @@ module.exports = { toHexString: toHexString }; -},{}],59:[function(require,module,exports){ +},{}],75:[function(require,module,exports){ /** * mux.js * @@ -15611,7 +15953,7 @@ module.exports = { metadataTsToSeconds: metadataTsToSeconds }; -},{}],60:[function(require,module,exports){ +},{}],76:[function(require,module,exports){ /** * mux.js * @@ -15766,7 +16108,7 @@ ExpGolomb = function(workingData) { module.exports = ExpGolomb; -},{}],61:[function(require,module,exports){ +},{}],77:[function(require,module,exports){ /** * mux.js * @@ -15909,7 +16251,7 @@ Stream.prototype.reset = function(flushSource) { module.exports = Stream; -},{}],62:[function(require,module,exports){ +},{}],78:[function(require,module,exports){ /* object-assign (c) Sindre Sorhus @@ -16001,7 +16343,7 @@ module.exports = shouldUseNative() ? Object.assign : function (target, source) { return to; }; -},{}],63:[function(require,module,exports){ +},{}],79:[function(require,module,exports){ (function (process){ 'use strict'; @@ -16050,7 +16392,7 @@ function nextTick(fn, arg1, arg2, arg3) { }).call(this,require('_process')) -},{"_process":8}],64:[function(require,module,exports){ +},{"_process":8}],80:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -16182,7 +16524,7 @@ Duplex.prototype._destroy = function (err, cb) { pna.nextTick(cb, err); }; -},{"./_stream_readable":66,"./_stream_writable":68,"core-util-is":10,"inherits":13,"process-nextick-args":63}],65:[function(require,module,exports){ +},{"./_stream_readable":82,"./_stream_writable":84,"core-util-is":10,"inherits":29,"process-nextick-args":79}],81:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -16230,7 +16572,7 @@ function PassThrough(options) { PassThrough.prototype._transform = function (chunk, encoding, cb) { cb(null, chunk); }; -},{"./_stream_transform":67,"core-util-is":10,"inherits":13}],66:[function(require,module,exports){ +},{"./_stream_transform":83,"core-util-is":10,"inherits":29}],82:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -17252,7 +17594,7 @@ function indexOf(xs, x) { return -1; } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./_stream_duplex":64,"./internal/streams/BufferList":69,"./internal/streams/destroy":70,"./internal/streams/stream":71,"_process":8,"core-util-is":10,"events":11,"inherits":13,"isarray":15,"process-nextick-args":63,"safe-buffer":74,"string_decoder/":75,"util":7}],67:[function(require,module,exports){ +},{"./_stream_duplex":80,"./internal/streams/BufferList":85,"./internal/streams/destroy":86,"./internal/streams/stream":87,"_process":8,"core-util-is":10,"events":27,"inherits":29,"isarray":31,"process-nextick-args":79,"safe-buffer":90,"string_decoder/":91,"util":7}],83:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -17467,7 +17809,7 @@ function done(stream, er, data) { return stream.push(null); } -},{"./_stream_duplex":64,"core-util-is":10,"inherits":13}],68:[function(require,module,exports){ +},{"./_stream_duplex":80,"core-util-is":10,"inherits":29}],84:[function(require,module,exports){ (function (process,global,setImmediate){ // Copyright Joyent, Inc. and other Node contributors. // @@ -18157,7 +18499,7 @@ Writable.prototype._destroy = function (err, cb) { cb(err); }; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("timers").setImmediate) -},{"./_stream_duplex":64,"./internal/streams/destroy":70,"./internal/streams/stream":71,"_process":8,"core-util-is":10,"inherits":13,"process-nextick-args":63,"safe-buffer":74,"timers":77,"util-deprecate":79}],69:[function(require,module,exports){ +},{"./_stream_duplex":80,"./internal/streams/destroy":86,"./internal/streams/stream":87,"_process":8,"core-util-is":10,"inherits":29,"process-nextick-args":79,"safe-buffer":90,"timers":93,"util-deprecate":100}],85:[function(require,module,exports){ 'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -18237,7 +18579,7 @@ if (util && util.inspect && util.inspect.custom) { return this.constructor.name + ' ' + obj; }; } -},{"safe-buffer":74,"util":7}],70:[function(require,module,exports){ +},{"safe-buffer":90,"util":7}],86:[function(require,module,exports){ 'use strict'; /*<replacement>*/ @@ -18312,10 +18654,10 @@ module.exports = { destroy: destroy, undestroy: undestroy }; -},{"process-nextick-args":63}],71:[function(require,module,exports){ +},{"process-nextick-args":79}],87:[function(require,module,exports){ module.exports = require('events').EventEmitter; -},{"events":11}],72:[function(require,module,exports){ +},{"events":27}],88:[function(require,module,exports){ exports = module.exports = require('./lib/_stream_readable.js'); exports.Stream = exports; exports.Readable = exports; @@ -18324,7 +18666,7 @@ exports.Duplex = require('./lib/_stream_duplex.js'); exports.Transform = require('./lib/_stream_transform.js'); exports.PassThrough = require('./lib/_stream_passthrough.js'); -},{"./lib/_stream_duplex.js":64,"./lib/_stream_passthrough.js":65,"./lib/_stream_readable.js":66,"./lib/_stream_transform.js":67,"./lib/_stream_writable.js":68}],73:[function(require,module,exports){ +},{"./lib/_stream_duplex.js":80,"./lib/_stream_passthrough.js":81,"./lib/_stream_readable.js":82,"./lib/_stream_transform.js":83,"./lib/_stream_writable.js":84}],89:[function(require,module,exports){ /*! @license Rematrix v0.7.0 Copyright 2020 Julian Lloyd. @@ -18631,7 +18973,7 @@ exports.PassThrough = require('./lib/_stream_passthrough.js'); }))); -},{}],74:[function(require,module,exports){ +},{}],90:[function(require,module,exports){ /* eslint-disable node/no-deprecated-api */ var buffer = require('buffer') var Buffer = buffer.Buffer @@ -18695,7 +19037,7 @@ SafeBuffer.allocUnsafeSlow = function (size) { return buffer.SlowBuffer(size) } -},{"buffer":9}],75:[function(require,module,exports){ +},{"buffer":9}],91:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -18992,7 +19334,7 @@ function simpleWrite(buf) { function simpleEnd(buf) { return buf && buf.length ? this.write(buf) : ''; } -},{"safe-buffer":74}],76:[function(require,module,exports){ +},{"safe-buffer":90}],92:[function(require,module,exports){ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : @@ -70035,7 +70377,7 @@ function simpleEnd(buf) { }))); -},{}],77:[function(require,module,exports){ +},{}],93:[function(require,module,exports){ (function (setImmediate,clearImmediate){ var nextTick = require('process/browser.js').nextTick; var apply = Function.prototype.apply; @@ -70114,9 +70456,79 @@ exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : delete immediateIds[id]; }; }).call(this,require("timers").setImmediate,require("timers").clearImmediate) -},{"process/browser.js":78,"timers":77}],78:[function(require,module,exports){ +},{"process/browser.js":94,"timers":93}],94:[function(require,module,exports){ arguments[4][8][0].apply(exports,arguments) -},{"dup":8}],79:[function(require,module,exports){ +},{"dup":8}],95:[function(require,module,exports){ +"use strict"; + +var isPrototype = require("../prototype/is"); + +module.exports = function (value) { + if (typeof value !== "function") return false; + + if (!hasOwnProperty.call(value, "length")) return false; + + try { + if (typeof value.length !== "number") return false; + if (typeof value.call !== "function") return false; + if (typeof value.apply !== "function") return false; + } catch (error) { + return false; + } + + return !isPrototype(value); +}; + +},{"../prototype/is":98}],96:[function(require,module,exports){ +"use strict"; + +var isValue = require("../value/is"); + +// prettier-ignore +var possibleTypes = { "object": true, "function": true, "undefined": true /* document.all */ }; + +module.exports = function (value) { + if (!isValue(value)) return false; + return hasOwnProperty.call(possibleTypes, typeof value); +}; + +},{"../value/is":99}],97:[function(require,module,exports){ +"use strict"; + +var isFunction = require("../function/is"); + +var classRe = /^\s*class[\s{/}]/, functionToString = Function.prototype.toString; + +module.exports = function (value) { + if (!isFunction(value)) return false; + if (classRe.test(functionToString.call(value))) return false; + return true; +}; + +},{"../function/is":95}],98:[function(require,module,exports){ +"use strict"; + +var isObject = require("../object/is"); + +module.exports = function (value) { + if (!isObject(value)) return false; + try { + if (!value.constructor) return false; + return value.constructor.prototype === value; + } catch (error) { + return false; + } +}; + +},{"../object/is":96}],99:[function(require,module,exports){ +"use strict"; + +// ES3 safe +var _undefined = void 0; + +module.exports = function (value) { return value !== _undefined && value !== null; }; + +},{}],100:[function(require,module,exports){ (function (global){ /** @@ -70187,11 +70599,11 @@ function config (name) { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],80:[function(require,module,exports){ +},{}],101:[function(require,module,exports){ arguments[4][3][0].apply(exports,arguments) -},{"dup":3}],81:[function(require,module,exports){ +},{"dup":3}],102:[function(require,module,exports){ arguments[4][4][0].apply(exports,arguments) -},{"./support/isBuffer":80,"_process":8,"dup":4,"inherits":13}],82:[function(require,module,exports){ +},{"./support/isBuffer":101,"_process":8,"dup":4,"inherits":29}],103:[function(require,module,exports){ var v1 = require('./v1'); var v4 = require('./v4'); @@ -70201,7 +70613,7 @@ uuid.v4 = v4; module.exports = uuid; -},{"./v1":85,"./v4":86}],83:[function(require,module,exports){ +},{"./v1":106,"./v4":107}],104:[function(require,module,exports){ /** * Convert array of 16 byte values to UUID string format of the form: * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX @@ -70229,7 +70641,7 @@ function bytesToUuid(buf, offset) { module.exports = bytesToUuid; -},{}],84:[function(require,module,exports){ +},{}],105:[function(require,module,exports){ // Unique ID creation requires a high quality random # generator. In the // browser this is a little complicated due to unknown quality of Math.random() // and inconsistent support for the `crypto` API. We do the best we can via @@ -70265,7 +70677,7 @@ if (getRandomValues) { }; } -},{}],85:[function(require,module,exports){ +},{}],106:[function(require,module,exports){ var rng = require('./lib/rng'); var bytesToUuid = require('./lib/bytesToUuid'); @@ -70376,7 +70788,7 @@ function v1(options, buf, offset) { module.exports = v1; -},{"./lib/bytesToUuid":83,"./lib/rng":84}],86:[function(require,module,exports){ +},{"./lib/bytesToUuid":104,"./lib/rng":105}],107:[function(require,module,exports){ var rng = require('./lib/rng'); var bytesToUuid = require('./lib/bytesToUuid'); @@ -70407,25 +70819,215 @@ function v4(options, buf, offset) { module.exports = v4; -},{"./lib/bytesToUuid":83,"./lib/rng":84}],87:[function(require,module,exports){ +},{"./lib/bytesToUuid":104,"./lib/rng":105}],108:[function(require,module,exports){ +var ee = require('event-emitter'); +const MUXJS = require('mux.js'); +const MP4 = MUXJS.mp4.generator; +const H264Stream = MUXJS.codecs.h264.H264Stream; + +const VIDEO_PROPERTIES = [ + 'width', + 'height', + 'profileIdc', + 'levelIdc', + 'profileCompatibility', + 'sarRatio' + ]; + +function getNALType(data) { + return (data.length > 4) ? data.readUInt8(4) & 0x1F : 0; +} + +function isKeyFrame(data) { + return getNALType(data) == 7; // SPS +} + +function concatNals(sample) { + let length = sample.size; + let data = new Uint8Array(length); + let view = new DataView(data.buffer); + let dataOffset = 0; + + for (var i=0; i<sample.units.length; ++i) { + view.setUint32(dataOffset, sample.units[i].data.byteLength); + dataOffset += 4; + data.set(sample.units[i].data, dataOffset); + dataOffset += sample.units[i].data.byteLength; + } + + sample.data = data; +} + +var createDefaultSample = function() { + return { + units: [], + data: null, + size: 0, + compositionTimeOffset: 1, + duration: 0, + dataOffset: 0, + flags: { + isLeading: 0, + dependsOn: 1, + isDependedOn: 0, + hasRedundancy: 0, + degradationPriority: 0, + isNonSyncSample: 1 + }, + keyFrame: true + }; + }; + +/** + * Convert FTL stream packets into MP4 fragments for use with MSE. It emits + * 'data' events with a single argument containing the MP4 fragment. + */ +function FTLRemux() { + this.frameset = 0; + this.source = 0; + this.channel = 0; + this.paused = false; + this.active = false; + + this.track = { + timelineStartInfo: { + baseMediaDecodeTime: 0 + }, + baseMediaDecodeTime: 0, + id: 0, + codec: 'avc', + type: 'video', + samples: [], + duration: 0 + }; + + this.h264 = new H264Stream(); + + this.h264.on('data', (nalUnit) => { + // record the track config + if (nalUnit.nalUnitType === 'seq_parameter_set_rbsp') { + this.track.config = nalUnit.config; + this.track.sps = [nalUnit.data]; + + VIDEO_PROPERTIES.forEach(function(prop) { + this.track[prop] = nalUnit.config[prop]; + }, this); + } + + if (nalUnit.nalUnitType === 'pic_parameter_set_rbsp') { + //pps = nalUnit.data; + this.track.pps = [nalUnit.data]; + } + + if (!this.init_seg && this.track.sps && this.track.pps) { + this.init_seg = true; + console.log("Init", this.track); + this.emit('data', MP4.initSegment([this.track])); + } + + let keyFrame = nalUnit.nalUnitType == 'slice_layer_without_partitioning_rbsp_idr'; + let sample = this.track.samples[0]; + sample.units.push(nalUnit); + sample.size += nalUnit.data.byteLength + 4; + + sample.keyFrame &= keyFrame; + + if (keyFrame) { + sample.flags.isNonSyncSample = 0; + sample.flags.dependsOn = 2; + } + }); + + this.mime = 'video/mp4; codecs="avc1.640028"'; + this.sequenceNo = 0; + this.seen_keyframe = false; + this.ts = 0; + this.dts = 0; + this.init_seg = false; +}; + +ee(FTLRemux.prototype); + +FTLRemux.prototype.push = function(spkt, pkt) { + if (this.paused || !this.active) { + return; + } + + if(pkt[0] === 2){ // H264 packet. + if (spkt[1] == this.frameset && spkt[2] == this.source && spkt[3] == this.channel) { + + if (!this.seen_keyframe) { + if (isKeyFrame(pkt[5])) { + console.log("Key frame ", spkt[0]); + this.seen_keyframe = true; + } + } + + if (this.seen_keyframe) { + if (this.ts == 0) this.ts = spkt[0]; + //if (this.track.samples.length > 0) console.error("Unfinished sample"); + this.dts += spkt[0]-this.ts; + + this.track.samples.push(createDefaultSample()); + + this.h264.push({ + type: 'video', + dts: this.dts, + pts: spkt[0], + data: pkt[5], + trackId: 0 + }); + this.h264.flush(); + + let sample = this.track.samples[0]; + concatNals(sample); + let delta = (spkt[0]-this.ts)*90; + sample.duration = (delta > 0) ? delta : 1000; + + let moof = MP4.moof(this.sequenceNo++, [this.track]); + let mdat = MP4.mdat(sample.data); + let result = new Uint8Array(moof.byteLength + mdat.byteLength); + //result.set(MP4.STYP); + result.set(moof); + result.set(mdat, moof.byteLength); + this.emit('data', result); + + this.track.samples = []; + this.track.baseMediaDecodeTime += delta; + + this.ts = spkt[0]; + } + } + } +} + +FTLRemux.prototype.select = function(frameset, source, channel) { + this.frameset = frameset; + this.source = source; + this.channel = channel; + + this.reset(); +} + +FTLRemux.prototype.reset = function() { + this.init_seg = false; + this.seen_keyframe = false; + this.ts = 0; + this.track.baseMediaDecodeTime = 0; + this.sequenceNo = 0; + this.active = true; +} + +module.exports = FTLRemux; + +},{"event-emitter":26,"mux.js":50}],109:[function(require,module,exports){ (function (Buffer){ const Peer = require('../../server/src/peer') const msgpack = require('msgpack5')(); const rematrix = require('rematrix'); const THREE = require('three'); -const MUXJS = require('mux.js'); -const MP4 = MUXJS.mp4.generator; -const H264Stream = MUXJS.codecs.h264.H264Stream; +const FTLRemux = require('./ftlremux'); //const VIDEO_PROPERTIES = require('../../node_modules/mux.js/lib/constants/video-properties.js'); - -const VIDEO_PROPERTIES = [ - 'width', - 'height', - 'profileIdc', - 'levelIdc', - 'profileCompatibility', - 'sarRatio' - ]; let current_data = {}; @@ -70551,50 +71153,6 @@ function FTLFrameset(id) { this.sources = {}; } -function getNALType(data) { - return (data.length > 4) ? data.readUInt8(4) & 0x1F : 0; -} - -function isKeyFrame(data) { - return getNALType(data) == 7; // SPS -} - -function concatNals(sample) { - let length = sample.size; - let data = new Uint8Array(length); - let view = new DataView(data.buffer); - let dataOffset = 0; - - for (var i=0; i<sample.units.length; ++i) { - view.setUint32(dataOffset, sample.units[i].data.byteLength); - dataOffset += 4; - data.set(sample.units[i].data, dataOffset); - dataOffset += sample.units[i].data.byteLength; - } - - sample.data = data; -} - -var createDefaultSample = function() { - return { - units: [], - data: null, - size: 0, - compositionTimeOffset: 1, - duration: 0, - dataOffset: 0, - flags: { - isLeading: 0, - dependsOn: 1, - isDependedOn: 0, - hasRedundancy: 0, - degradationPriority: 0, - isNonSyncSample: 1 - }, - keyFrame: true - }; - }; - function FTLStream(peer, uri, element) { this.uri = uri; this.peer = peer; @@ -70802,13 +71360,11 @@ function FTLStream(peer, uri, element) { });*/ let rxcount = 0; - let ts = 0; - let dts = 0; - let seen_keyframe = false; - let init_seg = false; - - this.h264 = new H264Stream(); + this.remux = new FTLRemux(); + this.remux.on('data', (data) => { + this.doAppend(data); + }); this.doAppend = function(data) { if (this.sourceBuffer.updating) { @@ -70824,78 +71380,7 @@ function FTLStream(peer, uri, element) { } } - this.h264.on('data', (nalUnit) => { - //console.log("NAL", nalUnit); - //this.segstream.push(data); - - //trackDecodeInfo.collectDtsInfo(track, nalUnit); - - // record the track config - if (nalUnit.nalUnitType === 'seq_parameter_set_rbsp') { - this.track.config = nalUnit.config; - this.track.sps = [nalUnit.data]; - - VIDEO_PROPERTIES.forEach(function(prop) { - this.track[prop] = nalUnit.config[prop]; - }, this); - } - - if (nalUnit.nalUnitType === 'pic_parameter_set_rbsp') { - //pps = nalUnit.data; - this.track.pps = [nalUnit.data]; - } - - if (!init_seg && this.track.sps && this.track.pps) { - init_seg = true; - console.log("Init", this.track); - this.doAppend(MP4.initSegment([this.track])); - } - - let keyFrame = nalUnit.nalUnitType == 'slice_layer_without_partitioning_rbsp_idr'; - - // buffer video until flush() is called - //nalUnits.push(nalUnit); - //if (keyFrame || !nalUnit.hasOwnProperty("nalUnitType")) { - /*this.track.samples.push({ - data: nalUnit.data, - duration: 1, - pts: nalUnit.pts, - dts: nalUnit.dts, - flags: { - isLeading: 0, - isDependedOn: 0, - hasRedundancy: 0, - degradPrio: 0, - isNonSyncSample: keyFrame ? 0 : 1, - dependsOn: keyFrame ? 2 : 1, - paddingValue: 0, - } - });*/ - - let sample = this.track.samples[0]; - sample.units.push(nalUnit); - sample.size += nalUnit.data.byteLength + 4; - - sample.keyFrame &= keyFrame; - - if (keyFrame) { - sample.flags.isNonSyncSample = 0; - sample.flags.dependsOn = 2; - } - //} - }); - - this.track = { - timelineStartInfo: { - baseMediaDecodeTime: 0 - }, - baseMediaDecodeTime: 0, - id: 0, - codec: 'avc', - type: 'video', - samples: [], - duration: 0 - }; + this.mime = 'video/mp4; codecs="avc1.640028"'; this.mediaSource = new MediaSource(); //this.element.play(); @@ -70908,13 +71393,8 @@ function FTLStream(peer, uri, element) { this.element.addEventListener('play', (e) => { console.log("Play"); - init_seg = false; - seen_keyframe = false; - ts = 0; - this.track.baseMediaDecodeTime = 0; - this.sequenceNo = 0; this.active = true; - this.start(0,0,0); + this.remux.select(0,0,0); }); this.mediaSource.addEventListener('sourceopen', (e) => { @@ -70945,9 +71425,7 @@ function FTLStream(peer, uri, element) { }); }); - this.mime = 'video/mp4; codecs="avc1.640028"'; this.queue = []; - this.sequenceNo = 0; this.element.src = URL.createObjectURL(this.mediaSource); @@ -70967,91 +71445,7 @@ function FTLStream(peer, uri, element) { //peer.send(current_data.uri, 0, [255,7,35,0,0,Buffer.alloc(0)], [1,0,255,0]); } - //console.log("NALU", getNALType(pckg[5])); - - if (!seen_keyframe) { - if (isKeyFrame(pckg[5])) { - console.log("Key frame ", streampckg[0]); - seen_keyframe = true; - } - } - - if (seen_keyframe) { - if (ts == 0) ts = streampckg[0]; - //if (this.track.samples.length > 0) console.error("Unfinished sample"); - dts += streampckg[0]-ts; - - this.track.samples.push(createDefaultSample()); - - this.h264.push({ - type: 'video', - dts: dts, - pts: streampckg[0], - data: pckg[5], - trackId: 0 - }); - this.h264.flush(); - - let sample = this.track.samples[0]; - /*if (sample.keyFrame) { - sample.flags.isNonSyncSample = 0; - sample.flags.dependsOn = 2; - }*/ - - concatNals(sample); - let delta = (streampckg[0]-ts)*90; - sample.duration = (delta > 0) ? delta : 1000; - - let moof = MP4.moof(this.sequenceNo++, [this.track]); - let mdat = MP4.mdat(sample.data); - let result = new Uint8Array(moof.byteLength + mdat.byteLength); - //result.set(MP4.STYP); - result.set(moof); - result.set(mdat, moof.byteLength); - this.doAppend(result); - - //this.doAppend(); - //this.doAppend(MP4.mdat(sample.data)); - this.track.samples = []; - this.track.baseMediaDecodeTime += delta; - - //this.segstream.flush(); - //if (isKeyFrame(pckg[5])) console.log("Key frame ", streampckg[0]); - /*function decode(value){ - this.converter.appendRawData(value); - } - decode(pckg[5]);*/ - //if (this.converter.sourceBuffer && this.converter.sourceBuffer.mode != "sequence") { - // this.converter.sourceBuffer.mode = 'sequence'; - //} - //this.converter.appendRawData(pckg[5], (streampckg[0]-ts)); - //this.converter.play(); - - /*if (ts > 0) { - this.converter.feed({ - video: pckg[5], - duration: streampckg[0]-ts - }); - } else { - this.converter.feed({ - video: pckg[5] - }); - }*/ - - ts = streampckg[0]; - } - - - /*else { - if (ts > 0) { - dts = streampckg[0] - ts; - console.log("Framerate = ", 1000/dts); - //this.converter = new VideoConverter.default(this.element, 31, 1); - - dts = 0; - } - ts = streampckg[0]; - }*/ + this.remux.push(streampckg, pckg); } } else if (pckg[0] === 103) { //console.log(msgpack.decode(pckg[5])); @@ -71121,6 +71515,8 @@ FTLStream.prototype.start = function(fs, source, channel) { this.current_source = source; this.current_channel = channel; + this.remux.select(fs, source, channel); + if (this.found) { this.peer.send(this.uri, 0, [1,fs,255,channel],[255,7,35,0,0,Buffer.alloc(0)]); } else { @@ -71235,7 +71631,7 @@ saveConfigs = async () => { const content = await rawResp.json(); } }).call(this,require("buffer").Buffer) -},{"../../server/src/peer":88,"buffer":9,"msgpack5":16,"mux.js":34,"rematrix":73,"three":76}],88:[function(require,module,exports){ +},{"../../server/src/peer":110,"./ftlremux":108,"buffer":9,"msgpack5":32,"rematrix":89,"three":92}],110:[function(require,module,exports){ (function (Buffer){ const msgpack = require('msgpack5')() , encode = msgpack.encode @@ -71524,7 +71920,7 @@ Peer.prototype.getUuid = function() { module.exports = Peer; }).call(this,require("buffer").Buffer) -},{"./utils/uuidParser":89,"buffer":9,"msgpack5":16,"uuid":82}],89:[function(require,module,exports){ +},{"./utils/uuidParser":111,"buffer":9,"msgpack5":32,"uuid":103}],111:[function(require,module,exports){ // Maps for number <-> hex string conversion var _byteToHex = []; var _hexToByte = {}; @@ -71579,4 +71975,4 @@ module.exports = { parse: parse, unparse: unparse }; -},{}]},{},[87]); +},{}]},{},[109]); diff --git a/web-service/public/js/ftlplayer.js b/web-service/public/js/ftlplayer.js new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/web-service/public/js/ftlremux.js b/web-service/public/js/ftlremux.js new file mode 100644 index 0000000000000000000000000000000000000000..4c5c722ca7519d40af06b4802ee5fe4f253f2b7f --- /dev/null +++ b/web-service/public/js/ftlremux.js @@ -0,0 +1,199 @@ +var ee = require('event-emitter'); +const MUXJS = require('mux.js'); +const MP4 = MUXJS.mp4.generator; +const H264Stream = MUXJS.codecs.h264.H264Stream; + +const VIDEO_PROPERTIES = [ + 'width', + 'height', + 'profileIdc', + 'levelIdc', + 'profileCompatibility', + 'sarRatio' + ]; + +function getNALType(data) { + return (data.length > 4) ? data.readUInt8(4) & 0x1F : 0; +} + +function isKeyFrame(data) { + return getNALType(data) == 7; // SPS +} + +function concatNals(sample) { + let length = sample.size; + let data = new Uint8Array(length); + let view = new DataView(data.buffer); + let dataOffset = 0; + + for (var i=0; i<sample.units.length; ++i) { + view.setUint32(dataOffset, sample.units[i].data.byteLength); + dataOffset += 4; + data.set(sample.units[i].data, dataOffset); + dataOffset += sample.units[i].data.byteLength; + } + + sample.data = data; +} + +var createDefaultSample = function() { + return { + units: [], + data: null, + size: 0, + compositionTimeOffset: 1, + duration: 0, + dataOffset: 0, + flags: { + isLeading: 0, + dependsOn: 1, + isDependedOn: 0, + hasRedundancy: 0, + degradationPriority: 0, + isNonSyncSample: 1 + }, + keyFrame: true + }; + }; + +/** + * Convert FTL stream packets into MP4 fragments for use with MSE. It emits + * 'data' events with a single argument containing the MP4 fragment. + */ +function FTLRemux() { + this.frameset = 0; + this.source = 0; + this.channel = 0; + this.paused = false; + this.active = false; + + this.track = { + timelineStartInfo: { + baseMediaDecodeTime: 0 + }, + baseMediaDecodeTime: 0, + id: 0, + codec: 'avc', + type: 'video', + samples: [], + duration: 0 + }; + + this.h264 = new H264Stream(); + + this.h264.on('data', (nalUnit) => { + // record the track config + if (nalUnit.nalUnitType === 'seq_parameter_set_rbsp') { + this.track.config = nalUnit.config; + this.track.sps = [nalUnit.data]; + + VIDEO_PROPERTIES.forEach(function(prop) { + this.track[prop] = nalUnit.config[prop]; + }, this); + } + + if (nalUnit.nalUnitType === 'pic_parameter_set_rbsp') { + //pps = nalUnit.data; + this.track.pps = [nalUnit.data]; + } + + if (!this.init_seg && this.track.sps && this.track.pps) { + this.init_seg = true; + console.log("Init", this.track); + this.emit('data', MP4.initSegment([this.track])); + } + + let keyFrame = nalUnit.nalUnitType == 'slice_layer_without_partitioning_rbsp_idr'; + let sample = this.track.samples[0]; + sample.units.push(nalUnit); + sample.size += nalUnit.data.byteLength + 4; + + sample.keyFrame &= keyFrame; + + if (keyFrame) { + sample.flags.isNonSyncSample = 0; + sample.flags.dependsOn = 2; + } + }); + + this.mime = 'video/mp4; codecs="avc1.640028"'; + this.sequenceNo = 0; + this.seen_keyframe = false; + this.ts = 0; + this.dts = 0; + this.init_seg = false; +}; + +ee(FTLRemux.prototype); + +FTLRemux.prototype.push = function(spkt, pkt) { + if (this.paused || !this.active) { + return; + } + + if(pkt[0] === 2){ // H264 packet. + if (spkt[1] == this.frameset && spkt[2] == this.source && spkt[3] == this.channel) { + + if (!this.seen_keyframe) { + if (isKeyFrame(pkt[5])) { + console.log("Key frame ", spkt[0]); + this.seen_keyframe = true; + } + } + + if (this.seen_keyframe) { + if (this.ts == 0) this.ts = spkt[0]; + //if (this.track.samples.length > 0) console.error("Unfinished sample"); + this.dts += spkt[0]-this.ts; + + this.track.samples.push(createDefaultSample()); + + this.h264.push({ + type: 'video', + dts: this.dts, + pts: spkt[0], + data: pkt[5], + trackId: 0 + }); + this.h264.flush(); + + let sample = this.track.samples[0]; + concatNals(sample); + let delta = (spkt[0]-this.ts)*90; + sample.duration = (delta > 0) ? delta : 1000; + + let moof = MP4.moof(this.sequenceNo++, [this.track]); + let mdat = MP4.mdat(sample.data); + let result = new Uint8Array(moof.byteLength + mdat.byteLength); + //result.set(MP4.STYP); + result.set(moof); + result.set(mdat, moof.byteLength); + this.emit('data', result); + + this.track.samples = []; + this.track.baseMediaDecodeTime += delta; + + this.ts = spkt[0]; + } + } + } +} + +FTLRemux.prototype.select = function(frameset, source, channel) { + this.frameset = frameset; + this.source = source; + this.channel = channel; + + this.reset(); +} + +FTLRemux.prototype.reset = function() { + this.init_seg = false; + this.seen_keyframe = false; + this.ts = 0; + this.track.baseMediaDecodeTime = 0; + this.sequenceNo = 0; + this.active = true; +} + +module.exports = FTLRemux; diff --git a/web-service/public/js/ftlstream.js b/web-service/public/js/ftlstream.js new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/web-service/public/js/index.js b/web-service/public/js/index.js index 3808bb6307b7d874fa40c611afc0ada1dbf7e300..a3a9dd464f746dbf44b0aedc7841be36a6bcd3b8 100644 --- a/web-service/public/js/index.js +++ b/web-service/public/js/index.js @@ -2,19 +2,8 @@ const Peer = require('../../server/src/peer') const msgpack = require('msgpack5')(); const rematrix = require('rematrix'); const THREE = require('three'); -const MUXJS = require('mux.js'); -const MP4 = MUXJS.mp4.generator; -const H264Stream = MUXJS.codecs.h264.H264Stream; +const FTLRemux = require('./ftlremux'); //const VIDEO_PROPERTIES = require('../../node_modules/mux.js/lib/constants/video-properties.js'); - -const VIDEO_PROPERTIES = [ - 'width', - 'height', - 'profileIdc', - 'levelIdc', - 'profileCompatibility', - 'sarRatio' - ]; let current_data = {}; @@ -140,50 +129,6 @@ function FTLFrameset(id) { this.sources = {}; } -function getNALType(data) { - return (data.length > 4) ? data.readUInt8(4) & 0x1F : 0; -} - -function isKeyFrame(data) { - return getNALType(data) == 7; // SPS -} - -function concatNals(sample) { - let length = sample.size; - let data = new Uint8Array(length); - let view = new DataView(data.buffer); - let dataOffset = 0; - - for (var i=0; i<sample.units.length; ++i) { - view.setUint32(dataOffset, sample.units[i].data.byteLength); - dataOffset += 4; - data.set(sample.units[i].data, dataOffset); - dataOffset += sample.units[i].data.byteLength; - } - - sample.data = data; -} - -var createDefaultSample = function() { - return { - units: [], - data: null, - size: 0, - compositionTimeOffset: 1, - duration: 0, - dataOffset: 0, - flags: { - isLeading: 0, - dependsOn: 1, - isDependedOn: 0, - hasRedundancy: 0, - degradationPriority: 0, - isNonSyncSample: 1 - }, - keyFrame: true - }; - }; - function FTLStream(peer, uri, element) { this.uri = uri; this.peer = peer; @@ -391,13 +336,11 @@ function FTLStream(peer, uri, element) { });*/ let rxcount = 0; - let ts = 0; - let dts = 0; - - let seen_keyframe = false; - let init_seg = false; - this.h264 = new H264Stream(); + this.remux = new FTLRemux(); + this.remux.on('data', (data) => { + this.doAppend(data); + }); this.doAppend = function(data) { if (this.sourceBuffer.updating) { @@ -413,78 +356,7 @@ function FTLStream(peer, uri, element) { } } - this.h264.on('data', (nalUnit) => { - //console.log("NAL", nalUnit); - //this.segstream.push(data); - - //trackDecodeInfo.collectDtsInfo(track, nalUnit); - - // record the track config - if (nalUnit.nalUnitType === 'seq_parameter_set_rbsp') { - this.track.config = nalUnit.config; - this.track.sps = [nalUnit.data]; - - VIDEO_PROPERTIES.forEach(function(prop) { - this.track[prop] = nalUnit.config[prop]; - }, this); - } - - if (nalUnit.nalUnitType === 'pic_parameter_set_rbsp') { - //pps = nalUnit.data; - this.track.pps = [nalUnit.data]; - } - - if (!init_seg && this.track.sps && this.track.pps) { - init_seg = true; - console.log("Init", this.track); - this.doAppend(MP4.initSegment([this.track])); - } - - let keyFrame = nalUnit.nalUnitType == 'slice_layer_without_partitioning_rbsp_idr'; - - // buffer video until flush() is called - //nalUnits.push(nalUnit); - //if (keyFrame || !nalUnit.hasOwnProperty("nalUnitType")) { - /*this.track.samples.push({ - data: nalUnit.data, - duration: 1, - pts: nalUnit.pts, - dts: nalUnit.dts, - flags: { - isLeading: 0, - isDependedOn: 0, - hasRedundancy: 0, - degradPrio: 0, - isNonSyncSample: keyFrame ? 0 : 1, - dependsOn: keyFrame ? 2 : 1, - paddingValue: 0, - } - });*/ - - let sample = this.track.samples[0]; - sample.units.push(nalUnit); - sample.size += nalUnit.data.byteLength + 4; - - sample.keyFrame &= keyFrame; - - if (keyFrame) { - sample.flags.isNonSyncSample = 0; - sample.flags.dependsOn = 2; - } - //} - }); - - this.track = { - timelineStartInfo: { - baseMediaDecodeTime: 0 - }, - baseMediaDecodeTime: 0, - id: 0, - codec: 'avc', - type: 'video', - samples: [], - duration: 0 - }; + this.mime = 'video/mp4; codecs="avc1.640028"'; this.mediaSource = new MediaSource(); //this.element.play(); @@ -497,13 +369,8 @@ function FTLStream(peer, uri, element) { this.element.addEventListener('play', (e) => { console.log("Play"); - init_seg = false; - seen_keyframe = false; - ts = 0; - this.track.baseMediaDecodeTime = 0; - this.sequenceNo = 0; this.active = true; - this.start(0,0,0); + this.remux.select(0,0,0); }); this.mediaSource.addEventListener('sourceopen', (e) => { @@ -534,9 +401,7 @@ function FTLStream(peer, uri, element) { }); }); - this.mime = 'video/mp4; codecs="avc1.640028"'; this.queue = []; - this.sequenceNo = 0; this.element.src = URL.createObjectURL(this.mediaSource); @@ -556,91 +421,7 @@ function FTLStream(peer, uri, element) { //peer.send(current_data.uri, 0, [255,7,35,0,0,Buffer.alloc(0)], [1,0,255,0]); } - //console.log("NALU", getNALType(pckg[5])); - - if (!seen_keyframe) { - if (isKeyFrame(pckg[5])) { - console.log("Key frame ", streampckg[0]); - seen_keyframe = true; - } - } - - if (seen_keyframe) { - if (ts == 0) ts = streampckg[0]; - //if (this.track.samples.length > 0) console.error("Unfinished sample"); - dts += streampckg[0]-ts; - - this.track.samples.push(createDefaultSample()); - - this.h264.push({ - type: 'video', - dts: dts, - pts: streampckg[0], - data: pckg[5], - trackId: 0 - }); - this.h264.flush(); - - let sample = this.track.samples[0]; - /*if (sample.keyFrame) { - sample.flags.isNonSyncSample = 0; - sample.flags.dependsOn = 2; - }*/ - - concatNals(sample); - let delta = (streampckg[0]-ts)*90; - sample.duration = (delta > 0) ? delta : 1000; - - let moof = MP4.moof(this.sequenceNo++, [this.track]); - let mdat = MP4.mdat(sample.data); - let result = new Uint8Array(moof.byteLength + mdat.byteLength); - //result.set(MP4.STYP); - result.set(moof); - result.set(mdat, moof.byteLength); - this.doAppend(result); - - //this.doAppend(); - //this.doAppend(MP4.mdat(sample.data)); - this.track.samples = []; - this.track.baseMediaDecodeTime += delta; - - //this.segstream.flush(); - //if (isKeyFrame(pckg[5])) console.log("Key frame ", streampckg[0]); - /*function decode(value){ - this.converter.appendRawData(value); - } - decode(pckg[5]);*/ - //if (this.converter.sourceBuffer && this.converter.sourceBuffer.mode != "sequence") { - // this.converter.sourceBuffer.mode = 'sequence'; - //} - //this.converter.appendRawData(pckg[5], (streampckg[0]-ts)); - //this.converter.play(); - - /*if (ts > 0) { - this.converter.feed({ - video: pckg[5], - duration: streampckg[0]-ts - }); - } else { - this.converter.feed({ - video: pckg[5] - }); - }*/ - - ts = streampckg[0]; - } - - - /*else { - if (ts > 0) { - dts = streampckg[0] - ts; - console.log("Framerate = ", 1000/dts); - //this.converter = new VideoConverter.default(this.element, 31, 1); - - dts = 0; - } - ts = streampckg[0]; - }*/ + this.remux.push(streampckg, pckg); } } else if (pckg[0] === 103) { //console.log(msgpack.decode(pckg[5])); @@ -710,6 +491,8 @@ FTLStream.prototype.start = function(fs, source, channel) { this.current_source = source; this.current_channel = channel; + this.remux.select(fs, source, channel); + if (this.found) { this.peer.send(this.uri, 0, [1,fs,255,channel],[255,7,35,0,0,Buffer.alloc(0)]); } else {