UNPKG

633 kBJavaScriptView Raw
1(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.flvjs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
2(function (process,global){
3/*!
4 * @overview es6-promise - a tiny implementation of Promises/A+.
5 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
6 * @license Licensed under MIT license
7 * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
8 * @version v4.2.5+7f2b526d
9 */
10
11(function (global, factory) {
12 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
13 typeof define === 'function' && define.amd ? define(factory) :
14 (global.ES6Promise = factory());
15}(this, (function () { 'use strict';
16
17function objectOrFunction(x) {
18 var type = typeof x;
19 return x !== null && (type === 'object' || type === 'function');
20}
21
22function isFunction(x) {
23 return typeof x === 'function';
24}
25
26
27
28var _isArray = void 0;
29if (Array.isArray) {
30 _isArray = Array.isArray;
31} else {
32 _isArray = function (x) {
33 return Object.prototype.toString.call(x) === '[object Array]';
34 };
35}
36
37var isArray = _isArray;
38
39var len = 0;
40var vertxNext = void 0;
41var customSchedulerFn = void 0;
42
43var asap = function asap(callback, arg) {
44 queue[len] = callback;
45 queue[len + 1] = arg;
46 len += 2;
47 if (len === 2) {
48 // If len is 2, that means that we need to schedule an async flush.
49 // If additional callbacks are queued before the queue is flushed, they
50 // will be processed by this flush that we are scheduling.
51 if (customSchedulerFn) {
52 customSchedulerFn(flush);
53 } else {
54 scheduleFlush();
55 }
56 }
57};
58
59function setScheduler(scheduleFn) {
60 customSchedulerFn = scheduleFn;
61}
62
63function setAsap(asapFn) {
64 asap = asapFn;
65}
66
67var browserWindow = typeof window !== 'undefined' ? window : undefined;
68var browserGlobal = browserWindow || {};
69var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
70var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
71
72// test for web worker but not in IE10
73var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
74
75// node
76function useNextTick() {
77 // node version 0.10.x displays a deprecation warning when nextTick is used recursively
78 // see https://github.com/cujojs/when/issues/410 for details
79 return function () {
80 return process.nextTick(flush);
81 };
82}
83
84// vertx
85function useVertxTimer() {
86 if (typeof vertxNext !== 'undefined') {
87 return function () {
88 vertxNext(flush);
89 };
90 }
91
92 return useSetTimeout();
93}
94
95function useMutationObserver() {
96 var iterations = 0;
97 var observer = new BrowserMutationObserver(flush);
98 var node = document.createTextNode('');
99 observer.observe(node, { characterData: true });
100
101 return function () {
102 node.data = iterations = ++iterations % 2;
103 };
104}
105
106// web worker
107function useMessageChannel() {
108 var channel = new MessageChannel();
109 channel.port1.onmessage = flush;
110 return function () {
111 return channel.port2.postMessage(0);
112 };
113}
114
115function useSetTimeout() {
116 // Store setTimeout reference so es6-promise will be unaffected by
117 // other code modifying setTimeout (like sinon.useFakeTimers())
118 var globalSetTimeout = setTimeout;
119 return function () {
120 return globalSetTimeout(flush, 1);
121 };
122}
123
124var queue = new Array(1000);
125function flush() {
126 for (var i = 0; i < len; i += 2) {
127 var callback = queue[i];
128 var arg = queue[i + 1];
129
130 callback(arg);
131
132 queue[i] = undefined;
133 queue[i + 1] = undefined;
134 }
135
136 len = 0;
137}
138
139function attemptVertx() {
140 try {
141 var vertx = Function('return this')().require('vertx');
142 vertxNext = vertx.runOnLoop || vertx.runOnContext;
143 return useVertxTimer();
144 } catch (e) {
145 return useSetTimeout();
146 }
147}
148
149var scheduleFlush = void 0;
150// Decide what async method to use to triggering processing of queued callbacks:
151if (isNode) {
152 scheduleFlush = useNextTick();
153} else if (BrowserMutationObserver) {
154 scheduleFlush = useMutationObserver();
155} else if (isWorker) {
156 scheduleFlush = useMessageChannel();
157} else if (browserWindow === undefined && typeof _dereq_ === 'function') {
158 scheduleFlush = attemptVertx();
159} else {
160 scheduleFlush = useSetTimeout();
161}
162
163function then(onFulfillment, onRejection) {
164 var parent = this;
165
166 var child = new this.constructor(noop);
167
168 if (child[PROMISE_ID] === undefined) {
169 makePromise(child);
170 }
171
172 var _state = parent._state;
173
174
175 if (_state) {
176 var callback = arguments[_state - 1];
177 asap(function () {
178 return invokeCallback(_state, child, callback, parent._result);
179 });
180 } else {
181 subscribe(parent, child, onFulfillment, onRejection);
182 }
183
184 return child;
185}
186
187/**
188 `Promise.resolve` returns a promise that will become resolved with the
189 passed `value`. It is shorthand for the following:
190
191 ```javascript
192 let promise = new Promise(function(resolve, reject){
193 resolve(1);
194 });
195
196 promise.then(function(value){
197 // value === 1
198 });
199 ```
200
201 Instead of writing the above, your code now simply becomes the following:
202
203 ```javascript
204 let promise = Promise.resolve(1);
205
206 promise.then(function(value){
207 // value === 1
208 });
209 ```
210
211 @method resolve
212 @static
213 @param {Any} value value that the returned promise will be resolved with
214 Useful for tooling.
215 @return {Promise} a promise that will become fulfilled with the given
216 `value`
217*/
218function resolve$1(object) {
219 /*jshint validthis:true */
220 var Constructor = this;
221
222 if (object && typeof object === 'object' && object.constructor === Constructor) {
223 return object;
224 }
225
226 var promise = new Constructor(noop);
227 resolve(promise, object);
228 return promise;
229}
230
231var PROMISE_ID = Math.random().toString(36).substring(2);
232
233function noop() {}
234
235var PENDING = void 0;
236var FULFILLED = 1;
237var REJECTED = 2;
238
239var TRY_CATCH_ERROR = { error: null };
240
241function selfFulfillment() {
242 return new TypeError("You cannot resolve a promise with itself");
243}
244
245function cannotReturnOwn() {
246 return new TypeError('A promises callback cannot return that same promise.');
247}
248
249function getThen(promise) {
250 try {
251 return promise.then;
252 } catch (error) {
253 TRY_CATCH_ERROR.error = error;
254 return TRY_CATCH_ERROR;
255 }
256}
257
258function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
259 try {
260 then$$1.call(value, fulfillmentHandler, rejectionHandler);
261 } catch (e) {
262 return e;
263 }
264}
265
266function handleForeignThenable(promise, thenable, then$$1) {
267 asap(function (promise) {
268 var sealed = false;
269 var error = tryThen(then$$1, thenable, function (value) {
270 if (sealed) {
271 return;
272 }
273 sealed = true;
274 if (thenable !== value) {
275 resolve(promise, value);
276 } else {
277 fulfill(promise, value);
278 }
279 }, function (reason) {
280 if (sealed) {
281 return;
282 }
283 sealed = true;
284
285 reject(promise, reason);
286 }, 'Settle: ' + (promise._label || ' unknown promise'));
287
288 if (!sealed && error) {
289 sealed = true;
290 reject(promise, error);
291 }
292 }, promise);
293}
294
295function handleOwnThenable(promise, thenable) {
296 if (thenable._state === FULFILLED) {
297 fulfill(promise, thenable._result);
298 } else if (thenable._state === REJECTED) {
299 reject(promise, thenable._result);
300 } else {
301 subscribe(thenable, undefined, function (value) {
302 return resolve(promise, value);
303 }, function (reason) {
304 return reject(promise, reason);
305 });
306 }
307}
308
309function handleMaybeThenable(promise, maybeThenable, then$$1) {
310 if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) {
311 handleOwnThenable(promise, maybeThenable);
312 } else {
313 if (then$$1 === TRY_CATCH_ERROR) {
314 reject(promise, TRY_CATCH_ERROR.error);
315 TRY_CATCH_ERROR.error = null;
316 } else if (then$$1 === undefined) {
317 fulfill(promise, maybeThenable);
318 } else if (isFunction(then$$1)) {
319 handleForeignThenable(promise, maybeThenable, then$$1);
320 } else {
321 fulfill(promise, maybeThenable);
322 }
323 }
324}
325
326function resolve(promise, value) {
327 if (promise === value) {
328 reject(promise, selfFulfillment());
329 } else if (objectOrFunction(value)) {
330 handleMaybeThenable(promise, value, getThen(value));
331 } else {
332 fulfill(promise, value);
333 }
334}
335
336function publishRejection(promise) {
337 if (promise._onerror) {
338 promise._onerror(promise._result);
339 }
340
341 publish(promise);
342}
343
344function fulfill(promise, value) {
345 if (promise._state !== PENDING) {
346 return;
347 }
348
349 promise._result = value;
350 promise._state = FULFILLED;
351
352 if (promise._subscribers.length !== 0) {
353 asap(publish, promise);
354 }
355}
356
357function reject(promise, reason) {
358 if (promise._state !== PENDING) {
359 return;
360 }
361 promise._state = REJECTED;
362 promise._result = reason;
363
364 asap(publishRejection, promise);
365}
366
367function subscribe(parent, child, onFulfillment, onRejection) {
368 var _subscribers = parent._subscribers;
369 var length = _subscribers.length;
370
371
372 parent._onerror = null;
373
374 _subscribers[length] = child;
375 _subscribers[length + FULFILLED] = onFulfillment;
376 _subscribers[length + REJECTED] = onRejection;
377
378 if (length === 0 && parent._state) {
379 asap(publish, parent);
380 }
381}
382
383function publish(promise) {
384 var subscribers = promise._subscribers;
385 var settled = promise._state;
386
387 if (subscribers.length === 0) {
388 return;
389 }
390
391 var child = void 0,
392 callback = void 0,
393 detail = promise._result;
394
395 for (var i = 0; i < subscribers.length; i += 3) {
396 child = subscribers[i];
397 callback = subscribers[i + settled];
398
399 if (child) {
400 invokeCallback(settled, child, callback, detail);
401 } else {
402 callback(detail);
403 }
404 }
405
406 promise._subscribers.length = 0;
407}
408
409function tryCatch(callback, detail) {
410 try {
411 return callback(detail);
412 } catch (e) {
413 TRY_CATCH_ERROR.error = e;
414 return TRY_CATCH_ERROR;
415 }
416}
417
418function invokeCallback(settled, promise, callback, detail) {
419 var hasCallback = isFunction(callback),
420 value = void 0,
421 error = void 0,
422 succeeded = void 0,
423 failed = void 0;
424
425 if (hasCallback) {
426 value = tryCatch(callback, detail);
427
428 if (value === TRY_CATCH_ERROR) {
429 failed = true;
430 error = value.error;
431 value.error = null;
432 } else {
433 succeeded = true;
434 }
435
436 if (promise === value) {
437 reject(promise, cannotReturnOwn());
438 return;
439 }
440 } else {
441 value = detail;
442 succeeded = true;
443 }
444
445 if (promise._state !== PENDING) {
446 // noop
447 } else if (hasCallback && succeeded) {
448 resolve(promise, value);
449 } else if (failed) {
450 reject(promise, error);
451 } else if (settled === FULFILLED) {
452 fulfill(promise, value);
453 } else if (settled === REJECTED) {
454 reject(promise, value);
455 }
456}
457
458function initializePromise(promise, resolver) {
459 try {
460 resolver(function resolvePromise(value) {
461 resolve(promise, value);
462 }, function rejectPromise(reason) {
463 reject(promise, reason);
464 });
465 } catch (e) {
466 reject(promise, e);
467 }
468}
469
470var id = 0;
471function nextId() {
472 return id++;
473}
474
475function makePromise(promise) {
476 promise[PROMISE_ID] = id++;
477 promise._state = undefined;
478 promise._result = undefined;
479 promise._subscribers = [];
480}
481
482function validationError() {
483 return new Error('Array Methods must be provided an Array');
484}
485
486var Enumerator = function () {
487 function Enumerator(Constructor, input) {
488 this._instanceConstructor = Constructor;
489 this.promise = new Constructor(noop);
490
491 if (!this.promise[PROMISE_ID]) {
492 makePromise(this.promise);
493 }
494
495 if (isArray(input)) {
496 this.length = input.length;
497 this._remaining = input.length;
498
499 this._result = new Array(this.length);
500
501 if (this.length === 0) {
502 fulfill(this.promise, this._result);
503 } else {
504 this.length = this.length || 0;
505 this._enumerate(input);
506 if (this._remaining === 0) {
507 fulfill(this.promise, this._result);
508 }
509 }
510 } else {
511 reject(this.promise, validationError());
512 }
513 }
514
515 Enumerator.prototype._enumerate = function _enumerate(input) {
516 for (var i = 0; this._state === PENDING && i < input.length; i++) {
517 this._eachEntry(input[i], i);
518 }
519 };
520
521 Enumerator.prototype._eachEntry = function _eachEntry(entry, i) {
522 var c = this._instanceConstructor;
523 var resolve$$1 = c.resolve;
524
525
526 if (resolve$$1 === resolve$1) {
527 var _then = getThen(entry);
528
529 if (_then === then && entry._state !== PENDING) {
530 this._settledAt(entry._state, i, entry._result);
531 } else if (typeof _then !== 'function') {
532 this._remaining--;
533 this._result[i] = entry;
534 } else if (c === Promise$1) {
535 var promise = new c(noop);
536 handleMaybeThenable(promise, entry, _then);
537 this._willSettleAt(promise, i);
538 } else {
539 this._willSettleAt(new c(function (resolve$$1) {
540 return resolve$$1(entry);
541 }), i);
542 }
543 } else {
544 this._willSettleAt(resolve$$1(entry), i);
545 }
546 };
547
548 Enumerator.prototype._settledAt = function _settledAt(state, i, value) {
549 var promise = this.promise;
550
551
552 if (promise._state === PENDING) {
553 this._remaining--;
554
555 if (state === REJECTED) {
556 reject(promise, value);
557 } else {
558 this._result[i] = value;
559 }
560 }
561
562 if (this._remaining === 0) {
563 fulfill(promise, this._result);
564 }
565 };
566
567 Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i) {
568 var enumerator = this;
569
570 subscribe(promise, undefined, function (value) {
571 return enumerator._settledAt(FULFILLED, i, value);
572 }, function (reason) {
573 return enumerator._settledAt(REJECTED, i, reason);
574 });
575 };
576
577 return Enumerator;
578}();
579
580/**
581 `Promise.all` accepts an array of promises, and returns a new promise which
582 is fulfilled with an array of fulfillment values for the passed promises, or
583 rejected with the reason of the first passed promise to be rejected. It casts all
584 elements of the passed iterable to promises as it runs this algorithm.
585
586 Example:
587
588 ```javascript
589 let promise1 = resolve(1);
590 let promise2 = resolve(2);
591 let promise3 = resolve(3);
592 let promises = [ promise1, promise2, promise3 ];
593
594 Promise.all(promises).then(function(array){
595 // The array here would be [ 1, 2, 3 ];
596 });
597 ```
598
599 If any of the `promises` given to `all` are rejected, the first promise
600 that is rejected will be given as an argument to the returned promises's
601 rejection handler. For example:
602
603 Example:
604
605 ```javascript
606 let promise1 = resolve(1);
607 let promise2 = reject(new Error("2"));
608 let promise3 = reject(new Error("3"));
609 let promises = [ promise1, promise2, promise3 ];
610
611 Promise.all(promises).then(function(array){
612 // Code here never runs because there are rejected promises!
613 }, function(error) {
614 // error.message === "2"
615 });
616 ```
617
618 @method all
619 @static
620 @param {Array} entries array of promises
621 @param {String} label optional string for labeling the promise.
622 Useful for tooling.
623 @return {Promise} promise that is fulfilled when all `promises` have been
624 fulfilled, or rejected if any of them become rejected.
625 @static
626*/
627function all(entries) {
628 return new Enumerator(this, entries).promise;
629}
630
631/**
632 `Promise.race` returns a new promise which is settled in the same way as the
633 first passed promise to settle.
634
635 Example:
636
637 ```javascript
638 let promise1 = new Promise(function(resolve, reject){
639 setTimeout(function(){
640 resolve('promise 1');
641 }, 200);
642 });
643
644 let promise2 = new Promise(function(resolve, reject){
645 setTimeout(function(){
646 resolve('promise 2');
647 }, 100);
648 });
649
650 Promise.race([promise1, promise2]).then(function(result){
651 // result === 'promise 2' because it was resolved before promise1
652 // was resolved.
653 });
654 ```
655
656 `Promise.race` is deterministic in that only the state of the first
657 settled promise matters. For example, even if other promises given to the
658 `promises` array argument are resolved, but the first settled promise has
659 become rejected before the other promises became fulfilled, the returned
660 promise will become rejected:
661
662 ```javascript
663 let promise1 = new Promise(function(resolve, reject){
664 setTimeout(function(){
665 resolve('promise 1');
666 }, 200);
667 });
668
669 let promise2 = new Promise(function(resolve, reject){
670 setTimeout(function(){
671 reject(new Error('promise 2'));
672 }, 100);
673 });
674
675 Promise.race([promise1, promise2]).then(function(result){
676 // Code here never runs
677 }, function(reason){
678 // reason.message === 'promise 2' because promise 2 became rejected before
679 // promise 1 became fulfilled
680 });
681 ```
682
683 An example real-world use case is implementing timeouts:
684
685 ```javascript
686 Promise.race([ajax('foo.json'), timeout(5000)])
687 ```
688
689 @method race
690 @static
691 @param {Array} promises array of promises to observe
692 Useful for tooling.
693 @return {Promise} a promise which settles in the same way as the first passed
694 promise to settle.
695*/
696function race(entries) {
697 /*jshint validthis:true */
698 var Constructor = this;
699
700 if (!isArray(entries)) {
701 return new Constructor(function (_, reject) {
702 return reject(new TypeError('You must pass an array to race.'));
703 });
704 } else {
705 return new Constructor(function (resolve, reject) {
706 var length = entries.length;
707 for (var i = 0; i < length; i++) {
708 Constructor.resolve(entries[i]).then(resolve, reject);
709 }
710 });
711 }
712}
713
714/**
715 `Promise.reject` returns a promise rejected with the passed `reason`.
716 It is shorthand for the following:
717
718 ```javascript
719 let promise = new Promise(function(resolve, reject){
720 reject(new Error('WHOOPS'));
721 });
722
723 promise.then(function(value){
724 // Code here doesn't run because the promise is rejected!
725 }, function(reason){
726 // reason.message === 'WHOOPS'
727 });
728 ```
729
730 Instead of writing the above, your code now simply becomes the following:
731
732 ```javascript
733 let promise = Promise.reject(new Error('WHOOPS'));
734
735 promise.then(function(value){
736 // Code here doesn't run because the promise is rejected!
737 }, function(reason){
738 // reason.message === 'WHOOPS'
739 });
740 ```
741
742 @method reject
743 @static
744 @param {Any} reason value that the returned promise will be rejected with.
745 Useful for tooling.
746 @return {Promise} a promise rejected with the given `reason`.
747*/
748function reject$1(reason) {
749 /*jshint validthis:true */
750 var Constructor = this;
751 var promise = new Constructor(noop);
752 reject(promise, reason);
753 return promise;
754}
755
756function needsResolver() {
757 throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
758}
759
760function needsNew() {
761 throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
762}
763
764/**
765 Promise objects represent the eventual result of an asynchronous operation. The
766 primary way of interacting with a promise is through its `then` method, which
767 registers callbacks to receive either a promise's eventual value or the reason
768 why the promise cannot be fulfilled.
769
770 Terminology
771 -----------
772
773 - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
774 - `thenable` is an object or function that defines a `then` method.
775 - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
776 - `exception` is a value that is thrown using the throw statement.
777 - `reason` is a value that indicates why a promise was rejected.
778 - `settled` the final resting state of a promise, fulfilled or rejected.
779
780 A promise can be in one of three states: pending, fulfilled, or rejected.
781
782 Promises that are fulfilled have a fulfillment value and are in the fulfilled
783 state. Promises that are rejected have a rejection reason and are in the
784 rejected state. A fulfillment value is never a thenable.
785
786 Promises can also be said to *resolve* a value. If this value is also a
787 promise, then the original promise's settled state will match the value's
788 settled state. So a promise that *resolves* a promise that rejects will
789 itself reject, and a promise that *resolves* a promise that fulfills will
790 itself fulfill.
791
792
793 Basic Usage:
794 ------------
795
796 ```js
797 let promise = new Promise(function(resolve, reject) {
798 // on success
799 resolve(value);
800
801 // on failure
802 reject(reason);
803 });
804
805 promise.then(function(value) {
806 // on fulfillment
807 }, function(reason) {
808 // on rejection
809 });
810 ```
811
812 Advanced Usage:
813 ---------------
814
815 Promises shine when abstracting away asynchronous interactions such as
816 `XMLHttpRequest`s.
817
818 ```js
819 function getJSON(url) {
820 return new Promise(function(resolve, reject){
821 let xhr = new XMLHttpRequest();
822
823 xhr.open('GET', url);
824 xhr.onreadystatechange = handler;
825 xhr.responseType = 'json';
826 xhr.setRequestHeader('Accept', 'application/json');
827 xhr.send();
828
829 function handler() {
830 if (this.readyState === this.DONE) {
831 if (this.status === 200) {
832 resolve(this.response);
833 } else {
834 reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
835 }
836 }
837 };
838 });
839 }
840
841 getJSON('/posts.json').then(function(json) {
842 // on fulfillment
843 }, function(reason) {
844 // on rejection
845 });
846 ```
847
848 Unlike callbacks, promises are great composable primitives.
849
850 ```js
851 Promise.all([
852 getJSON('/posts'),
853 getJSON('/comments')
854 ]).then(function(values){
855 values[0] // => postsJSON
856 values[1] // => commentsJSON
857
858 return values;
859 });
860 ```
861
862 @class Promise
863 @param {Function} resolver
864 Useful for tooling.
865 @constructor
866*/
867
868var Promise$1 = function () {
869 function Promise(resolver) {
870 this[PROMISE_ID] = nextId();
871 this._result = this._state = undefined;
872 this._subscribers = [];
873
874 if (noop !== resolver) {
875 typeof resolver !== 'function' && needsResolver();
876 this instanceof Promise ? initializePromise(this, resolver) : needsNew();
877 }
878 }
879
880 /**
881 The primary way of interacting with a promise is through its `then` method,
882 which registers callbacks to receive either a promise's eventual value or the
883 reason why the promise cannot be fulfilled.
884 ```js
885 findUser().then(function(user){
886 // user is available
887 }, function(reason){
888 // user is unavailable, and you are given the reason why
889 });
890 ```
891 Chaining
892 --------
893 The return value of `then` is itself a promise. This second, 'downstream'
894 promise is resolved with the return value of the first promise's fulfillment
895 or rejection handler, or rejected if the handler throws an exception.
896 ```js
897 findUser().then(function (user) {
898 return user.name;
899 }, function (reason) {
900 return 'default name';
901 }).then(function (userName) {
902 // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
903 // will be `'default name'`
904 });
905 findUser().then(function (user) {
906 throw new Error('Found user, but still unhappy');
907 }, function (reason) {
908 throw new Error('`findUser` rejected and we're unhappy');
909 }).then(function (value) {
910 // never reached
911 }, function (reason) {
912 // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
913 // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
914 });
915 ```
916 If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
917 ```js
918 findUser().then(function (user) {
919 throw new PedagogicalException('Upstream error');
920 }).then(function (value) {
921 // never reached
922 }).then(function (value) {
923 // never reached
924 }, function (reason) {
925 // The `PedgagocialException` is propagated all the way down to here
926 });
927 ```
928 Assimilation
929 ------------
930 Sometimes the value you want to propagate to a downstream promise can only be
931 retrieved asynchronously. This can be achieved by returning a promise in the
932 fulfillment or rejection handler. The downstream promise will then be pending
933 until the returned promise is settled. This is called *assimilation*.
934 ```js
935 findUser().then(function (user) {
936 return findCommentsByAuthor(user);
937 }).then(function (comments) {
938 // The user's comments are now available
939 });
940 ```
941 If the assimliated promise rejects, then the downstream promise will also reject.
942 ```js
943 findUser().then(function (user) {
944 return findCommentsByAuthor(user);
945 }).then(function (comments) {
946 // If `findCommentsByAuthor` fulfills, we'll have the value here
947 }, function (reason) {
948 // If `findCommentsByAuthor` rejects, we'll have the reason here
949 });
950 ```
951 Simple Example
952 --------------
953 Synchronous Example
954 ```javascript
955 let result;
956 try {
957 result = findResult();
958 // success
959 } catch(reason) {
960 // failure
961 }
962 ```
963 Errback Example
964 ```js
965 findResult(function(result, err){
966 if (err) {
967 // failure
968 } else {
969 // success
970 }
971 });
972 ```
973 Promise Example;
974 ```javascript
975 findResult().then(function(result){
976 // success
977 }, function(reason){
978 // failure
979 });
980 ```
981 Advanced Example
982 --------------
983 Synchronous Example
984 ```javascript
985 let author, books;
986 try {
987 author = findAuthor();
988 books = findBooksByAuthor(author);
989 // success
990 } catch(reason) {
991 // failure
992 }
993 ```
994 Errback Example
995 ```js
996 function foundBooks(books) {
997 }
998 function failure(reason) {
999 }
1000 findAuthor(function(author, err){
1001 if (err) {
1002 failure(err);
1003 // failure
1004 } else {
1005 try {
1006 findBoooksByAuthor(author, function(books, err) {
1007 if (err) {
1008 failure(err);
1009 } else {
1010 try {
1011 foundBooks(books);
1012 } catch(reason) {
1013 failure(reason);
1014 }
1015 }
1016 });
1017 } catch(error) {
1018 failure(err);
1019 }
1020 // success
1021 }
1022 });
1023 ```
1024 Promise Example;
1025 ```javascript
1026 findAuthor().
1027 then(findBooksByAuthor).
1028 then(function(books){
1029 // found books
1030 }).catch(function(reason){
1031 // something went wrong
1032 });
1033 ```
1034 @method then
1035 @param {Function} onFulfilled
1036 @param {Function} onRejected
1037 Useful for tooling.
1038 @return {Promise}
1039 */
1040
1041 /**
1042 `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
1043 as the catch block of a try/catch statement.
1044 ```js
1045 function findAuthor(){
1046 throw new Error('couldn't find that author');
1047 }
1048 // synchronous
1049 try {
1050 findAuthor();
1051 } catch(reason) {
1052 // something went wrong
1053 }
1054 // async with promises
1055 findAuthor().catch(function(reason){
1056 // something went wrong
1057 });
1058 ```
1059 @method catch
1060 @param {Function} onRejection
1061 Useful for tooling.
1062 @return {Promise}
1063 */
1064
1065
1066 Promise.prototype.catch = function _catch(onRejection) {
1067 return this.then(null, onRejection);
1068 };
1069
1070 /**
1071 `finally` will be invoked regardless of the promise's fate just as native
1072 try/catch/finally behaves
1073
1074 Synchronous example:
1075
1076 ```js
1077 findAuthor() {
1078 if (Math.random() > 0.5) {
1079 throw new Error();
1080 }
1081 return new Author();
1082 }
1083
1084 try {
1085 return findAuthor(); // succeed or fail
1086 } catch(error) {
1087 return findOtherAuther();
1088 } finally {
1089 // always runs
1090 // doesn't affect the return value
1091 }
1092 ```
1093
1094 Asynchronous example:
1095
1096 ```js
1097 findAuthor().catch(function(reason){
1098 return findOtherAuther();
1099 }).finally(function(){
1100 // author was either found, or not
1101 });
1102 ```
1103
1104 @method finally
1105 @param {Function} callback
1106 @return {Promise}
1107 */
1108
1109
1110 Promise.prototype.finally = function _finally(callback) {
1111 var promise = this;
1112 var constructor = promise.constructor;
1113
1114 if (isFunction(callback)) {
1115 return promise.then(function (value) {
1116 return constructor.resolve(callback()).then(function () {
1117 return value;
1118 });
1119 }, function (reason) {
1120 return constructor.resolve(callback()).then(function () {
1121 throw reason;
1122 });
1123 });
1124 }
1125
1126 return promise.then(callback, callback);
1127 };
1128
1129 return Promise;
1130}();
1131
1132Promise$1.prototype.then = then;
1133Promise$1.all = all;
1134Promise$1.race = race;
1135Promise$1.resolve = resolve$1;
1136Promise$1.reject = reject$1;
1137Promise$1._setScheduler = setScheduler;
1138Promise$1._setAsap = setAsap;
1139Promise$1._asap = asap;
1140
1141/*global self*/
1142function polyfill() {
1143 var local = void 0;
1144
1145 if (typeof global !== 'undefined') {
1146 local = global;
1147 } else if (typeof self !== 'undefined') {
1148 local = self;
1149 } else {
1150 try {
1151 local = Function('return this')();
1152 } catch (e) {
1153 throw new Error('polyfill failed because global object is unavailable in this environment');
1154 }
1155 }
1156
1157 var P = local.Promise;
1158
1159 if (P) {
1160 var promiseToString = null;
1161 try {
1162 promiseToString = Object.prototype.toString.call(P.resolve());
1163 } catch (e) {
1164 // silently ignored
1165 }
1166
1167 if (promiseToString === '[object Promise]' && !P.cast) {
1168 return;
1169 }
1170 }
1171
1172 local.Promise = Promise$1;
1173}
1174
1175// Strange compat..
1176Promise$1.polyfill = polyfill;
1177Promise$1.Promise = Promise$1;
1178
1179return Promise$1;
1180
1181})));
1182
1183
1184
1185
1186
1187}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1188
1189},{"_process":3}],2:[function(_dereq_,module,exports){
1190// Copyright Joyent, Inc. and other Node contributors.
1191//
1192// Permission is hereby granted, free of charge, to any person obtaining a
1193// copy of this software and associated documentation files (the
1194// "Software"), to deal in the Software without restriction, including
1195// without limitation the rights to use, copy, modify, merge, publish,
1196// distribute, sublicense, and/or sell copies of the Software, and to permit
1197// persons to whom the Software is furnished to do so, subject to the
1198// following conditions:
1199//
1200// The above copyright notice and this permission notice shall be included
1201// in all copies or substantial portions of the Software.
1202//
1203// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1204// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1205// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
1206// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
1207// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1208// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
1209// USE OR OTHER DEALINGS IN THE SOFTWARE.
1210
1211function EventEmitter() {
1212 this._events = this._events || {};
1213 this._maxListeners = this._maxListeners || undefined;
1214}
1215module.exports = EventEmitter;
1216
1217// Backwards-compat with node 0.10.x
1218EventEmitter.EventEmitter = EventEmitter;
1219
1220EventEmitter.prototype._events = undefined;
1221EventEmitter.prototype._maxListeners = undefined;
1222
1223// By default EventEmitters will print a warning if more than 10 listeners are
1224// added to it. This is a useful default which helps finding memory leaks.
1225EventEmitter.defaultMaxListeners = 10;
1226
1227// Obviously not all Emitters should be limited to 10. This function allows
1228// that to be increased. Set to zero for unlimited.
1229EventEmitter.prototype.setMaxListeners = function(n) {
1230 if (!isNumber(n) || n < 0 || isNaN(n))
1231 throw TypeError('n must be a positive number');
1232 this._maxListeners = n;
1233 return this;
1234};
1235
1236EventEmitter.prototype.emit = function(type) {
1237 var er, handler, len, args, i, listeners;
1238
1239 if (!this._events)
1240 this._events = {};
1241
1242 // If there is no 'error' event listener then throw.
1243 if (type === 'error') {
1244 if (!this._events.error ||
1245 (isObject(this._events.error) && !this._events.error.length)) {
1246 er = arguments[1];
1247 if (er instanceof Error) {
1248 throw er; // Unhandled 'error' event
1249 } else {
1250 // At least give some kind of context to the user
1251 var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
1252 err.context = er;
1253 throw err;
1254 }
1255 }
1256 }
1257
1258 handler = this._events[type];
1259
1260 if (isUndefined(handler))
1261 return false;
1262
1263 if (isFunction(handler)) {
1264 switch (arguments.length) {
1265 // fast cases
1266 case 1:
1267 handler.call(this);
1268 break;
1269 case 2:
1270 handler.call(this, arguments[1]);
1271 break;
1272 case 3:
1273 handler.call(this, arguments[1], arguments[2]);
1274 break;
1275 // slower
1276 default:
1277 args = Array.prototype.slice.call(arguments, 1);
1278 handler.apply(this, args);
1279 }
1280 } else if (isObject(handler)) {
1281 args = Array.prototype.slice.call(arguments, 1);
1282 listeners = handler.slice();
1283 len = listeners.length;
1284 for (i = 0; i < len; i++)
1285 listeners[i].apply(this, args);
1286 }
1287
1288 return true;
1289};
1290
1291EventEmitter.prototype.addListener = function(type, listener) {
1292 var m;
1293
1294 if (!isFunction(listener))
1295 throw TypeError('listener must be a function');
1296
1297 if (!this._events)
1298 this._events = {};
1299
1300 // To avoid recursion in the case that type === "newListener"! Before
1301 // adding it to the listeners, first emit "newListener".
1302 if (this._events.newListener)
1303 this.emit('newListener', type,
1304 isFunction(listener.listener) ?
1305 listener.listener : listener);
1306
1307 if (!this._events[type])
1308 // Optimize the case of one listener. Don't need the extra array object.
1309 this._events[type] = listener;
1310 else if (isObject(this._events[type]))
1311 // If we've already got an array, just append.
1312 this._events[type].push(listener);
1313 else
1314 // Adding the second element, need to change to array.
1315 this._events[type] = [this._events[type], listener];
1316
1317 // Check for listener leak
1318 if (isObject(this._events[type]) && !this._events[type].warned) {
1319 if (!isUndefined(this._maxListeners)) {
1320 m = this._maxListeners;
1321 } else {
1322 m = EventEmitter.defaultMaxListeners;
1323 }
1324
1325 if (m && m > 0 && this._events[type].length > m) {
1326 this._events[type].warned = true;
1327 console.error('(node) warning: possible EventEmitter memory ' +
1328 'leak detected. %d listeners added. ' +
1329 'Use emitter.setMaxListeners() to increase limit.',
1330 this._events[type].length);
1331 if (typeof console.trace === 'function') {
1332 // not supported in IE 10
1333 console.trace();
1334 }
1335 }
1336 }
1337
1338 return this;
1339};
1340
1341EventEmitter.prototype.on = EventEmitter.prototype.addListener;
1342
1343EventEmitter.prototype.once = function(type, listener) {
1344 if (!isFunction(listener))
1345 throw TypeError('listener must be a function');
1346
1347 var fired = false;
1348
1349 function g() {
1350 this.removeListener(type, g);
1351
1352 if (!fired) {
1353 fired = true;
1354 listener.apply(this, arguments);
1355 }
1356 }
1357
1358 g.listener = listener;
1359 this.on(type, g);
1360
1361 return this;
1362};
1363
1364// emits a 'removeListener' event iff the listener was removed
1365EventEmitter.prototype.removeListener = function(type, listener) {
1366 var list, position, length, i;
1367
1368 if (!isFunction(listener))
1369 throw TypeError('listener must be a function');
1370
1371 if (!this._events || !this._events[type])
1372 return this;
1373
1374 list = this._events[type];
1375 length = list.length;
1376 position = -1;
1377
1378 if (list === listener ||
1379 (isFunction(list.listener) && list.listener === listener)) {
1380 delete this._events[type];
1381 if (this._events.removeListener)
1382 this.emit('removeListener', type, listener);
1383
1384 } else if (isObject(list)) {
1385 for (i = length; i-- > 0;) {
1386 if (list[i] === listener ||
1387 (list[i].listener && list[i].listener === listener)) {
1388 position = i;
1389 break;
1390 }
1391 }
1392
1393 if (position < 0)
1394 return this;
1395
1396 if (list.length === 1) {
1397 list.length = 0;
1398 delete this._events[type];
1399 } else {
1400 list.splice(position, 1);
1401 }
1402
1403 if (this._events.removeListener)
1404 this.emit('removeListener', type, listener);
1405 }
1406
1407 return this;
1408};
1409
1410EventEmitter.prototype.removeAllListeners = function(type) {
1411 var key, listeners;
1412
1413 if (!this._events)
1414 return this;
1415
1416 // not listening for removeListener, no need to emit
1417 if (!this._events.removeListener) {
1418 if (arguments.length === 0)
1419 this._events = {};
1420 else if (this._events[type])
1421 delete this._events[type];
1422 return this;
1423 }
1424
1425 // emit removeListener for all listeners on all events
1426 if (arguments.length === 0) {
1427 for (key in this._events) {
1428 if (key === 'removeListener') continue;
1429 this.removeAllListeners(key);
1430 }
1431 this.removeAllListeners('removeListener');
1432 this._events = {};
1433 return this;
1434 }
1435
1436 listeners = this._events[type];
1437
1438 if (isFunction(listeners)) {
1439 this.removeListener(type, listeners);
1440 } else if (listeners) {
1441 // LIFO order
1442 while (listeners.length)
1443 this.removeListener(type, listeners[listeners.length - 1]);
1444 }
1445 delete this._events[type];
1446
1447 return this;
1448};
1449
1450EventEmitter.prototype.listeners = function(type) {
1451 var ret;
1452 if (!this._events || !this._events[type])
1453 ret = [];
1454 else if (isFunction(this._events[type]))
1455 ret = [this._events[type]];
1456 else
1457 ret = this._events[type].slice();
1458 return ret;
1459};
1460
1461EventEmitter.prototype.listenerCount = function(type) {
1462 if (this._events) {
1463 var evlistener = this._events[type];
1464
1465 if (isFunction(evlistener))
1466 return 1;
1467 else if (evlistener)
1468 return evlistener.length;
1469 }
1470 return 0;
1471};
1472
1473EventEmitter.listenerCount = function(emitter, type) {
1474 return emitter.listenerCount(type);
1475};
1476
1477function isFunction(arg) {
1478 return typeof arg === 'function';
1479}
1480
1481function isNumber(arg) {
1482 return typeof arg === 'number';
1483}
1484
1485function isObject(arg) {
1486 return typeof arg === 'object' && arg !== null;
1487}
1488
1489function isUndefined(arg) {
1490 return arg === void 0;
1491}
1492
1493},{}],3:[function(_dereq_,module,exports){
1494// shim for using process in browser
1495var process = module.exports = {};
1496
1497// cached from whatever global is present so that test runners that stub it
1498// don't break things. But we need to wrap it in a try catch in case it is
1499// wrapped in strict mode code which doesn't define any globals. It's inside a
1500// function because try/catches deoptimize in certain engines.
1501
1502var cachedSetTimeout;
1503var cachedClearTimeout;
1504
1505function defaultSetTimout() {
1506 throw new Error('setTimeout has not been defined');
1507}
1508function defaultClearTimeout () {
1509 throw new Error('clearTimeout has not been defined');
1510}
1511(function () {
1512 try {
1513 if (typeof setTimeout === 'function') {
1514 cachedSetTimeout = setTimeout;
1515 } else {
1516 cachedSetTimeout = defaultSetTimout;
1517 }
1518 } catch (e) {
1519 cachedSetTimeout = defaultSetTimout;
1520 }
1521 try {
1522 if (typeof clearTimeout === 'function') {
1523 cachedClearTimeout = clearTimeout;
1524 } else {
1525 cachedClearTimeout = defaultClearTimeout;
1526 }
1527 } catch (e) {
1528 cachedClearTimeout = defaultClearTimeout;
1529 }
1530} ())
1531function runTimeout(fun) {
1532 if (cachedSetTimeout === setTimeout) {
1533 //normal enviroments in sane situations
1534 return setTimeout(fun, 0);
1535 }
1536 // if setTimeout wasn't available but was latter defined
1537 if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
1538 cachedSetTimeout = setTimeout;
1539 return setTimeout(fun, 0);
1540 }
1541 try {
1542 // when when somebody has screwed with setTimeout but no I.E. maddness
1543 return cachedSetTimeout(fun, 0);
1544 } catch(e){
1545 try {
1546 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
1547 return cachedSetTimeout.call(null, fun, 0);
1548 } catch(e){
1549 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
1550 return cachedSetTimeout.call(this, fun, 0);
1551 }
1552 }
1553
1554
1555}
1556function runClearTimeout(marker) {
1557 if (cachedClearTimeout === clearTimeout) {
1558 //normal enviroments in sane situations
1559 return clearTimeout(marker);
1560 }
1561 // if clearTimeout wasn't available but was latter defined
1562 if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
1563 cachedClearTimeout = clearTimeout;
1564 return clearTimeout(marker);
1565 }
1566 try {
1567 // when when somebody has screwed with setTimeout but no I.E. maddness
1568 return cachedClearTimeout(marker);
1569 } catch (e){
1570 try {
1571 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
1572 return cachedClearTimeout.call(null, marker);
1573 } catch (e){
1574 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
1575 // Some versions of I.E. have different rules for clearTimeout vs setTimeout
1576 return cachedClearTimeout.call(this, marker);
1577 }
1578 }
1579
1580
1581
1582}
1583var queue = [];
1584var draining = false;
1585var currentQueue;
1586var queueIndex = -1;
1587
1588function cleanUpNextTick() {
1589 if (!draining || !currentQueue) {
1590 return;
1591 }
1592 draining = false;
1593 if (currentQueue.length) {
1594 queue = currentQueue.concat(queue);
1595 } else {
1596 queueIndex = -1;
1597 }
1598 if (queue.length) {
1599 drainQueue();
1600 }
1601}
1602
1603function drainQueue() {
1604 if (draining) {
1605 return;
1606 }
1607 var timeout = runTimeout(cleanUpNextTick);
1608 draining = true;
1609
1610 var len = queue.length;
1611 while(len) {
1612 currentQueue = queue;
1613 queue = [];
1614 while (++queueIndex < len) {
1615 if (currentQueue) {
1616 currentQueue[queueIndex].run();
1617 }
1618 }
1619 queueIndex = -1;
1620 len = queue.length;
1621 }
1622 currentQueue = null;
1623 draining = false;
1624 runClearTimeout(timeout);
1625}
1626
1627process.nextTick = function (fun) {
1628 var args = new Array(arguments.length - 1);
1629 if (arguments.length > 1) {
1630 for (var i = 1; i < arguments.length; i++) {
1631 args[i - 1] = arguments[i];
1632 }
1633 }
1634 queue.push(new Item(fun, args));
1635 if (queue.length === 1 && !draining) {
1636 runTimeout(drainQueue);
1637 }
1638};
1639
1640// v8 likes predictible objects
1641function Item(fun, array) {
1642 this.fun = fun;
1643 this.array = array;
1644}
1645Item.prototype.run = function () {
1646 this.fun.apply(null, this.array);
1647};
1648process.title = 'browser';
1649process.browser = true;
1650process.env = {};
1651process.argv = [];
1652process.version = ''; // empty string to avoid regexp issues
1653process.versions = {};
1654
1655function noop() {}
1656
1657process.on = noop;
1658process.addListener = noop;
1659process.once = noop;
1660process.off = noop;
1661process.removeListener = noop;
1662process.removeAllListeners = noop;
1663process.emit = noop;
1664process.prependListener = noop;
1665process.prependOnceListener = noop;
1666
1667process.listeners = function (name) { return [] }
1668
1669process.binding = function (name) {
1670 throw new Error('process.binding is not supported');
1671};
1672
1673process.cwd = function () { return '/' };
1674process.chdir = function (dir) {
1675 throw new Error('process.chdir is not supported');
1676};
1677process.umask = function() { return 0; };
1678
1679},{}],4:[function(_dereq_,module,exports){
1680var bundleFn = arguments[3];
1681var sources = arguments[4];
1682var cache = arguments[5];
1683
1684var stringify = JSON.stringify;
1685
1686module.exports = function (fn, options) {
1687 var wkey;
1688 var cacheKeys = Object.keys(cache);
1689
1690 for (var i = 0, l = cacheKeys.length; i < l; i++) {
1691 var key = cacheKeys[i];
1692 var exp = cache[key].exports;
1693 // Using babel as a transpiler to use esmodule, the export will always
1694 // be an object with the default export as a property of it. To ensure
1695 // the existing api and babel esmodule exports are both supported we
1696 // check for both
1697 if (exp === fn || exp && exp.default === fn) {
1698 wkey = key;
1699 break;
1700 }
1701 }
1702
1703 if (!wkey) {
1704 wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
1705 var wcache = {};
1706 for (var i = 0, l = cacheKeys.length; i < l; i++) {
1707 var key = cacheKeys[i];
1708 wcache[key] = key;
1709 }
1710 sources[wkey] = [
1711 'function(require,module,exports){' + fn + '(self); }',
1712 wcache
1713 ];
1714 }
1715 var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
1716
1717 var scache = {}; scache[wkey] = wkey;
1718 sources[skey] = [
1719 'function(require,module,exports){' +
1720 // try to call default if defined to also support babel esmodule exports
1721 'var f = require(' + stringify(wkey) + ');' +
1722 '(f.default ? f.default : f)(self);' +
1723 '}',
1724 scache
1725 ];
1726
1727 var workerSources = {};
1728 resolveSources(skey);
1729
1730 function resolveSources(key) {
1731 workerSources[key] = true;
1732
1733 for (var depPath in sources[key][1]) {
1734 var depKey = sources[key][1][depPath];
1735 if (!workerSources[depKey]) {
1736 resolveSources(depKey);
1737 }
1738 }
1739 }
1740
1741 var src = '(' + bundleFn + ')({'
1742 + Object.keys(workerSources).map(function (key) {
1743 return stringify(key) + ':['
1744 + sources[key][0]
1745 + ',' + stringify(sources[key][1]) + ']'
1746 ;
1747 }).join(',')
1748 + '},{},[' + stringify(skey) + '])'
1749 ;
1750
1751 var URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
1752
1753 var blob = new Blob([src], { type: 'text/javascript' });
1754 if (options && options.bare) { return blob; }
1755 var workerUrl = URL.createObjectURL(blob);
1756 var worker = new Worker(workerUrl);
1757 worker.objectURL = workerUrl;
1758 return worker;
1759};
1760
1761},{}],5:[function(_dereq_,module,exports){
1762'use strict';
1763
1764Object.defineProperty(exports, "__esModule", {
1765 value: true
1766});
1767exports.createDefaultConfig = createDefaultConfig;
1768/*
1769 * Copyright (C) 2016 Bilibili. All Rights Reserved.
1770 *
1771 * @author zheng qian <xqq@xqq.im>
1772 *
1773 * Licensed under the Apache License, Version 2.0 (the "License");
1774 * you may not use this file except in compliance with the License.
1775 * You may obtain a copy of the License at
1776 *
1777 * http://www.apache.org/licenses/LICENSE-2.0
1778 *
1779 * Unless required by applicable law or agreed to in writing, software
1780 * distributed under the License is distributed on an "AS IS" BASIS,
1781 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1782 * See the License for the specific language governing permissions and
1783 * limitations under the License.
1784 */
1785
1786var defaultConfig = exports.defaultConfig = {
1787 enableWorker: false,
1788 enableStashBuffer: true,
1789 stashInitialSize: undefined,
1790
1791 isLive: false,
1792
1793 lazyLoad: true,
1794 lazyLoadMaxDuration: 3 * 60,
1795 lazyLoadRecoverDuration: 30,
1796 deferLoadAfterSourceOpen: true,
1797
1798 // autoCleanupSourceBuffer: default as false, leave unspecified
1799 autoCleanupMaxBackwardDuration: 3 * 60,
1800 autoCleanupMinBackwardDuration: 2 * 60,
1801
1802 statisticsInfoReportInterval: 600,
1803
1804 fixAudioTimestampGap: true,
1805
1806 accurateSeek: false,
1807 seekType: 'range', // [range, param, custom]
1808 seekParamStart: 'bstart',
1809 seekParamEnd: 'bend',
1810 rangeLoadZeroStart: false,
1811 customSeekHandler: undefined,
1812 reuseRedirectedURL: false,
1813 // referrerPolicy: leave as unspecified
1814
1815 headers: undefined,
1816 customLoader: undefined
1817};
1818
1819function createDefaultConfig() {
1820 return Object.assign({}, defaultConfig);
1821}
1822
1823},{}],6:[function(_dereq_,module,exports){
1824'use strict';
1825
1826Object.defineProperty(exports, "__esModule", {
1827 value: true
1828});
1829
1830var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
1831 * Copyright (C) 2016 Bilibili. All Rights Reserved.
1832 *
1833 * @author zheng qian <xqq@xqq.im>
1834 *
1835 * Licensed under the Apache License, Version 2.0 (the "License");
1836 * you may not use this file except in compliance with the License.
1837 * You may obtain a copy of the License at
1838 *
1839 * http://www.apache.org/licenses/LICENSE-2.0
1840 *
1841 * Unless required by applicable law or agreed to in writing, software
1842 * distributed under the License is distributed on an "AS IS" BASIS,
1843 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1844 * See the License for the specific language governing permissions and
1845 * limitations under the License.
1846 */
1847
1848var _ioController = _dereq_('../io/io-controller.js');
1849
1850var _ioController2 = _interopRequireDefault(_ioController);
1851
1852var _config = _dereq_('../config.js');
1853
1854function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
1855
1856function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
1857
1858var Features = function () {
1859 function Features() {
1860 _classCallCheck(this, Features);
1861 }
1862
1863 _createClass(Features, null, [{
1864 key: 'supportMSEH264Playback',
1865 value: function supportMSEH264Playback() {
1866 return window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');
1867 }
1868 }, {
1869 key: 'supportNetworkStreamIO',
1870 value: function supportNetworkStreamIO() {
1871 var ioctl = new _ioController2.default({}, (0, _config.createDefaultConfig)());
1872 var loaderType = ioctl.loaderType;
1873 ioctl.destroy();
1874 return loaderType == 'fetch-stream-loader' || loaderType == 'xhr-moz-chunked-loader';
1875 }
1876 }, {
1877 key: 'getNetworkLoaderTypeName',
1878 value: function getNetworkLoaderTypeName() {
1879 var ioctl = new _ioController2.default({}, (0, _config.createDefaultConfig)());
1880 var loaderType = ioctl.loaderType;
1881 ioctl.destroy();
1882 return loaderType;
1883 }
1884 }, {
1885 key: 'supportNativeMediaPlayback',
1886 value: function supportNativeMediaPlayback(mimeType) {
1887 if (Features.videoElement == undefined) {
1888 Features.videoElement = window.document.createElement('video');
1889 }
1890 var canPlay = Features.videoElement.canPlayType(mimeType);
1891 return canPlay === 'probably' || canPlay == 'maybe';
1892 }
1893 }, {
1894 key: 'getFeatureList',
1895 value: function getFeatureList() {
1896 var features = {
1897 mseFlvPlayback: false,
1898 mseLiveFlvPlayback: false,
1899 networkStreamIO: false,
1900 networkLoaderName: '',
1901 nativeMP4H264Playback: false,
1902 nativeWebmVP8Playback: false,
1903 nativeWebmVP9Playback: false
1904 };
1905
1906 features.mseFlvPlayback = Features.supportMSEH264Playback();
1907 features.networkStreamIO = Features.supportNetworkStreamIO();
1908 features.networkLoaderName = Features.getNetworkLoaderTypeName();
1909 features.mseLiveFlvPlayback = features.mseFlvPlayback && features.networkStreamIO;
1910 features.nativeMP4H264Playback = Features.supportNativeMediaPlayback('video/mp4; codecs="avc1.42001E, mp4a.40.2"');
1911 features.nativeWebmVP8Playback = Features.supportNativeMediaPlayback('video/webm; codecs="vp8.0, vorbis"');
1912 features.nativeWebmVP9Playback = Features.supportNativeMediaPlayback('video/webm; codecs="vp9"');
1913
1914 return features;
1915 }
1916 }]);
1917
1918 return Features;
1919}();
1920
1921exports.default = Features;
1922
1923},{"../config.js":5,"../io/io-controller.js":23}],7:[function(_dereq_,module,exports){
1924"use strict";
1925
1926Object.defineProperty(exports, "__esModule", {
1927 value: true
1928});
1929
1930var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
1931
1932function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
1933
1934/*
1935 * Copyright (C) 2016 Bilibili. All Rights Reserved.
1936 *
1937 * @author zheng qian <xqq@xqq.im>
1938 *
1939 * Licensed under the Apache License, Version 2.0 (the "License");
1940 * you may not use this file except in compliance with the License.
1941 * You may obtain a copy of the License at
1942 *
1943 * http://www.apache.org/licenses/LICENSE-2.0
1944 *
1945 * Unless required by applicable law or agreed to in writing, software
1946 * distributed under the License is distributed on an "AS IS" BASIS,
1947 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1948 * See the License for the specific language governing permissions and
1949 * limitations under the License.
1950 */
1951
1952var MediaInfo = function () {
1953 function MediaInfo() {
1954 _classCallCheck(this, MediaInfo);
1955
1956 this.mimeType = null;
1957 this.duration = null;
1958
1959 this.hasAudio = null;
1960 this.hasVideo = null;
1961 this.audioCodec = null;
1962 this.videoCodec = null;
1963 this.audioDataRate = null;
1964 this.videoDataRate = null;
1965
1966 this.audioSampleRate = null;
1967 this.audioChannelCount = null;
1968
1969 this.width = null;
1970 this.height = null;
1971 this.fps = null;
1972 this.profile = null;
1973 this.level = null;
1974 this.refFrames = null;
1975 this.chromaFormat = null;
1976 this.sarNum = null;
1977 this.sarDen = null;
1978
1979 this.metadata = null;
1980 this.segments = null; // MediaInfo[]
1981 this.segmentCount = null;
1982 this.hasKeyframesIndex = null;
1983 this.keyframesIndex = null;
1984 }
1985
1986 _createClass(MediaInfo, [{
1987 key: "isComplete",
1988 value: function isComplete() {
1989 var audioInfoComplete = this.hasAudio === false || this.hasAudio === true && this.audioCodec != null && this.audioSampleRate != null && this.audioChannelCount != null;
1990
1991 var videoInfoComplete = this.hasVideo === false || this.hasVideo === true && this.videoCodec != null && this.width != null && this.height != null && this.fps != null && this.profile != null && this.level != null && this.refFrames != null && this.chromaFormat != null && this.sarNum != null && this.sarDen != null;
1992
1993 // keyframesIndex may not be present
1994 return this.mimeType != null && this.duration != null && this.metadata != null && this.hasKeyframesIndex != null && audioInfoComplete && videoInfoComplete;
1995 }
1996 }, {
1997 key: "isSeekable",
1998 value: function isSeekable() {
1999 return this.hasKeyframesIndex === true;
2000 }
2001 }, {
2002 key: "getNearestKeyframe",
2003 value: function getNearestKeyframe(milliseconds) {
2004 if (this.keyframesIndex == null) {
2005 return null;
2006 }
2007
2008 var table = this.keyframesIndex;
2009 var keyframeIdx = this._search(table.times, milliseconds);
2010
2011 return {
2012 index: keyframeIdx,
2013 milliseconds: table.times[keyframeIdx],
2014 fileposition: table.filepositions[keyframeIdx]
2015 };
2016 }
2017 }, {
2018 key: "_search",
2019 value: function _search(list, value) {
2020 var idx = 0;
2021
2022 var last = list.length - 1;
2023 var mid = 0;
2024 var lbound = 0;
2025 var ubound = last;
2026
2027 if (value < list[0]) {
2028 idx = 0;
2029 lbound = ubound + 1; // skip search
2030 }
2031
2032 while (lbound <= ubound) {
2033 mid = lbound + Math.floor((ubound - lbound) / 2);
2034 if (mid === last || value >= list[mid] && value < list[mid + 1]) {
2035 idx = mid;
2036 break;
2037 } else if (list[mid] < value) {
2038 lbound = mid + 1;
2039 } else {
2040 ubound = mid - 1;
2041 }
2042 }
2043
2044 return idx;
2045 }
2046 }]);
2047
2048 return MediaInfo;
2049}();
2050
2051exports.default = MediaInfo;
2052
2053},{}],8:[function(_dereq_,module,exports){
2054"use strict";
2055
2056Object.defineProperty(exports, "__esModule", {
2057 value: true
2058});
2059
2060var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
2061
2062function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2063
2064/*
2065 * Copyright (C) 2016 Bilibili. All Rights Reserved.
2066 *
2067 * @author zheng qian <xqq@xqq.im>
2068 *
2069 * Licensed under the Apache License, Version 2.0 (the "License");
2070 * you may not use this file except in compliance with the License.
2071 * You may obtain a copy of the License at
2072 *
2073 * http://www.apache.org/licenses/LICENSE-2.0
2074 *
2075 * Unless required by applicable law or agreed to in writing, software
2076 * distributed under the License is distributed on an "AS IS" BASIS,
2077 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2078 * See the License for the specific language governing permissions and
2079 * limitations under the License.
2080 */
2081
2082// Represents an media sample (audio / video)
2083var SampleInfo = exports.SampleInfo = function SampleInfo(dts, pts, duration, originalDts, isSync) {
2084 _classCallCheck(this, SampleInfo);
2085
2086 this.dts = dts;
2087 this.pts = pts;
2088 this.duration = duration;
2089 this.originalDts = originalDts;
2090 this.isSyncPoint = isSync;
2091 this.fileposition = null;
2092};
2093
2094// Media Segment concept is defined in Media Source Extensions spec.
2095// Particularly in ISO BMFF format, an Media Segment contains a moof box followed by a mdat box.
2096
2097
2098var MediaSegmentInfo = exports.MediaSegmentInfo = function () {
2099 function MediaSegmentInfo() {
2100 _classCallCheck(this, MediaSegmentInfo);
2101
2102 this.beginDts = 0;
2103 this.endDts = 0;
2104 this.beginPts = 0;
2105 this.endPts = 0;
2106 this.originalBeginDts = 0;
2107 this.originalEndDts = 0;
2108 this.syncPoints = []; // SampleInfo[n], for video IDR frames only
2109 this.firstSample = null; // SampleInfo
2110 this.lastSample = null; // SampleInfo
2111 }
2112
2113 _createClass(MediaSegmentInfo, [{
2114 key: "appendSyncPoint",
2115 value: function appendSyncPoint(sampleInfo) {
2116 // also called Random Access Point
2117 sampleInfo.isSyncPoint = true;
2118 this.syncPoints.push(sampleInfo);
2119 }
2120 }]);
2121
2122 return MediaSegmentInfo;
2123}();
2124
2125// Ordered list for recording video IDR frames, sorted by originalDts
2126
2127
2128var IDRSampleList = exports.IDRSampleList = function () {
2129 function IDRSampleList() {
2130 _classCallCheck(this, IDRSampleList);
2131
2132 this._list = [];
2133 }
2134
2135 _createClass(IDRSampleList, [{
2136 key: "clear",
2137 value: function clear() {
2138 this._list = [];
2139 }
2140 }, {
2141 key: "appendArray",
2142 value: function appendArray(syncPoints) {
2143 var list = this._list;
2144
2145 if (syncPoints.length === 0) {
2146 return;
2147 }
2148
2149 if (list.length > 0 && syncPoints[0].originalDts < list[list.length - 1].originalDts) {
2150 this.clear();
2151 }
2152
2153 Array.prototype.push.apply(list, syncPoints);
2154 }
2155 }, {
2156 key: "getLastSyncPointBeforeDts",
2157 value: function getLastSyncPointBeforeDts(dts) {
2158 if (this._list.length == 0) {
2159 return null;
2160 }
2161
2162 var list = this._list;
2163 var idx = 0;
2164 var last = list.length - 1;
2165 var mid = 0;
2166 var lbound = 0;
2167 var ubound = last;
2168
2169 if (dts < list[0].dts) {
2170 idx = 0;
2171 lbound = ubound + 1;
2172 }
2173
2174 while (lbound <= ubound) {
2175 mid = lbound + Math.floor((ubound - lbound) / 2);
2176 if (mid === last || dts >= list[mid].dts && dts < list[mid + 1].dts) {
2177 idx = mid;
2178 break;
2179 } else if (list[mid].dts < dts) {
2180 lbound = mid + 1;
2181 } else {
2182 ubound = mid - 1;
2183 }
2184 }
2185 return this._list[idx];
2186 }
2187 }]);
2188
2189 return IDRSampleList;
2190}();
2191
2192// Data structure for recording information of media segments in single track.
2193
2194
2195var MediaSegmentInfoList = exports.MediaSegmentInfoList = function () {
2196 function MediaSegmentInfoList(type) {
2197 _classCallCheck(this, MediaSegmentInfoList);
2198
2199 this._type = type;
2200 this._list = [];
2201 this._lastAppendLocation = -1; // cached last insert location
2202 }
2203
2204 _createClass(MediaSegmentInfoList, [{
2205 key: "isEmpty",
2206 value: function isEmpty() {
2207 return this._list.length === 0;
2208 }
2209 }, {
2210 key: "clear",
2211 value: function clear() {
2212 this._list = [];
2213 this._lastAppendLocation = -1;
2214 }
2215 }, {
2216 key: "_searchNearestSegmentBefore",
2217 value: function _searchNearestSegmentBefore(originalBeginDts) {
2218 var list = this._list;
2219 if (list.length === 0) {
2220 return -2;
2221 }
2222 var last = list.length - 1;
2223 var mid = 0;
2224 var lbound = 0;
2225 var ubound = last;
2226
2227 var idx = 0;
2228
2229 if (originalBeginDts < list[0].originalBeginDts) {
2230 idx = -1;
2231 return idx;
2232 }
2233
2234 while (lbound <= ubound) {
2235 mid = lbound + Math.floor((ubound - lbound) / 2);
2236 if (mid === last || originalBeginDts > list[mid].lastSample.originalDts && originalBeginDts < list[mid + 1].originalBeginDts) {
2237 idx = mid;
2238 break;
2239 } else if (list[mid].originalBeginDts < originalBeginDts) {
2240 lbound = mid + 1;
2241 } else {
2242 ubound = mid - 1;
2243 }
2244 }
2245 return idx;
2246 }
2247 }, {
2248 key: "_searchNearestSegmentAfter",
2249 value: function _searchNearestSegmentAfter(originalBeginDts) {
2250 return this._searchNearestSegmentBefore(originalBeginDts) + 1;
2251 }
2252 }, {
2253 key: "append",
2254 value: function append(mediaSegmentInfo) {
2255 var list = this._list;
2256 var msi = mediaSegmentInfo;
2257 var lastAppendIdx = this._lastAppendLocation;
2258 var insertIdx = 0;
2259
2260 if (lastAppendIdx !== -1 && lastAppendIdx < list.length && msi.originalBeginDts >= list[lastAppendIdx].lastSample.originalDts && (lastAppendIdx === list.length - 1 || lastAppendIdx < list.length - 1 && msi.originalBeginDts < list[lastAppendIdx + 1].originalBeginDts)) {
2261 insertIdx = lastAppendIdx + 1; // use cached location idx
2262 } else {
2263 if (list.length > 0) {
2264 insertIdx = this._searchNearestSegmentBefore(msi.originalBeginDts) + 1;
2265 }
2266 }
2267
2268 this._lastAppendLocation = insertIdx;
2269 this._list.splice(insertIdx, 0, msi);
2270 }
2271 }, {
2272 key: "getLastSegmentBefore",
2273 value: function getLastSegmentBefore(originalBeginDts) {
2274 var idx = this._searchNearestSegmentBefore(originalBeginDts);
2275 if (idx >= 0) {
2276 return this._list[idx];
2277 } else {
2278 // -1
2279 return null;
2280 }
2281 }
2282 }, {
2283 key: "getLastSampleBefore",
2284 value: function getLastSampleBefore(originalBeginDts) {
2285 var segment = this.getLastSegmentBefore(originalBeginDts);
2286 if (segment != null) {
2287 return segment.lastSample;
2288 } else {
2289 return null;
2290 }
2291 }
2292 }, {
2293 key: "getLastSyncPointBefore",
2294 value: function getLastSyncPointBefore(originalBeginDts) {
2295 var segmentIdx = this._searchNearestSegmentBefore(originalBeginDts);
2296 var syncPoints = this._list[segmentIdx].syncPoints;
2297 while (syncPoints.length === 0 && segmentIdx > 0) {
2298 segmentIdx--;
2299 syncPoints = this._list[segmentIdx].syncPoints;
2300 }
2301 if (syncPoints.length > 0) {
2302 return syncPoints[syncPoints.length - 1];
2303 } else {
2304 return null;
2305 }
2306 }
2307 }, {
2308 key: "type",
2309 get: function get() {
2310 return this._type;
2311 }
2312 }, {
2313 key: "length",
2314 get: function get() {
2315 return this._list.length;
2316 }
2317 }]);
2318
2319 return MediaSegmentInfoList;
2320}();
2321
2322},{}],9:[function(_dereq_,module,exports){
2323'use strict';
2324
2325Object.defineProperty(exports, "__esModule", {
2326 value: true
2327});
2328
2329var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
2330 * Copyright (C) 2016 Bilibili. All Rights Reserved.
2331 *
2332 * @author zheng qian <xqq@xqq.im>
2333 *
2334 * Licensed under the Apache License, Version 2.0 (the "License");
2335 * you may not use this file except in compliance with the License.
2336 * You may obtain a copy of the License at
2337 *
2338 * http://www.apache.org/licenses/LICENSE-2.0
2339 *
2340 * Unless required by applicable law or agreed to in writing, software
2341 * distributed under the License is distributed on an "AS IS" BASIS,
2342 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2343 * See the License for the specific language governing permissions and
2344 * limitations under the License.
2345 */
2346
2347var _events = _dereq_('events');
2348
2349var _events2 = _interopRequireDefault(_events);
2350
2351var _logger = _dereq_('../utils/logger.js');
2352
2353var _logger2 = _interopRequireDefault(_logger);
2354
2355var _browser = _dereq_('../utils/browser.js');
2356
2357var _browser2 = _interopRequireDefault(_browser);
2358
2359var _mseEvents = _dereq_('./mse-events.js');
2360
2361var _mseEvents2 = _interopRequireDefault(_mseEvents);
2362
2363var _mediaSegmentInfo = _dereq_('./media-segment-info.js');
2364
2365var _exception = _dereq_('../utils/exception.js');
2366
2367function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2368
2369function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2370
2371// Media Source Extensions controller
2372var MSEController = function () {
2373 function MSEController(config) {
2374 _classCallCheck(this, MSEController);
2375
2376 this.TAG = 'MSEController';
2377
2378 this._config = config;
2379 this._emitter = new _events2.default();
2380
2381 if (this._config.isLive && this._config.autoCleanupSourceBuffer == undefined) {
2382 // For live stream, do auto cleanup by default
2383 this._config.autoCleanupSourceBuffer = true;
2384 }
2385
2386 this.e = {
2387 onSourceOpen: this._onSourceOpen.bind(this),
2388 onSourceEnded: this._onSourceEnded.bind(this),
2389 onSourceClose: this._onSourceClose.bind(this),
2390 onSourceBufferError: this._onSourceBufferError.bind(this),
2391 onSourceBufferUpdateEnd: this._onSourceBufferUpdateEnd.bind(this)
2392 };
2393
2394 this._mediaSource = null;
2395 this._mediaSourceObjectURL = null;
2396 this._mediaElement = null;
2397
2398 this._isBufferFull = false;
2399 this._hasPendingEos = false;
2400
2401 this._requireSetMediaDuration = false;
2402 this._pendingMediaDuration = 0;
2403
2404 this._pendingSourceBufferInit = [];
2405 this._mimeTypes = {
2406 video: null,
2407 audio: null
2408 };
2409 this._sourceBuffers = {
2410 video: null,
2411 audio: null
2412 };
2413 this._lastInitSegments = {
2414 video: null,
2415 audio: null
2416 };
2417 this._pendingSegments = {
2418 video: [],
2419 audio: []
2420 };
2421 this._pendingRemoveRanges = {
2422 video: [],
2423 audio: []
2424 };
2425 this._idrList = new _mediaSegmentInfo.IDRSampleList();
2426 }
2427
2428 _createClass(MSEController, [{
2429 key: 'destroy',
2430 value: function destroy() {
2431 if (this._mediaElement || this._mediaSource) {
2432 this.detachMediaElement();
2433 }
2434 this.e = null;
2435 this._emitter.removeAllListeners();
2436 this._emitter = null;
2437 }
2438 }, {
2439 key: 'on',
2440 value: function on(event, listener) {
2441 this._emitter.addListener(event, listener);
2442 }
2443 }, {
2444 key: 'off',
2445 value: function off(event, listener) {
2446 this._emitter.removeListener(event, listener);
2447 }
2448 }, {
2449 key: 'attachMediaElement',
2450 value: function attachMediaElement(mediaElement) {
2451 if (this._mediaSource) {
2452 throw new _exception.IllegalStateException('MediaSource has been attached to an HTMLMediaElement!');
2453 }
2454 var ms = this._mediaSource = new window.MediaSource();
2455 ms.addEventListener('sourceopen', this.e.onSourceOpen);
2456 ms.addEventListener('sourceended', this.e.onSourceEnded);
2457 ms.addEventListener('sourceclose', this.e.onSourceClose);
2458
2459 this._mediaElement = mediaElement;
2460 this._mediaSourceObjectURL = window.URL.createObjectURL(this._mediaSource);
2461 mediaElement.src = this._mediaSourceObjectURL;
2462 }
2463 }, {
2464 key: 'detachMediaElement',
2465 value: function detachMediaElement() {
2466 if (this._mediaSource) {
2467 var ms = this._mediaSource;
2468 for (var type in this._sourceBuffers) {
2469 // pending segments should be discard
2470 var ps = this._pendingSegments[type];
2471 ps.splice(0, ps.length);
2472 this._pendingSegments[type] = null;
2473 this._pendingRemoveRanges[type] = null;
2474 this._lastInitSegments[type] = null;
2475
2476 // remove all sourcebuffers
2477 var sb = this._sourceBuffers[type];
2478 if (sb) {
2479 if (ms.readyState !== 'closed') {
2480 // ms edge can throw an error: Unexpected call to method or property access
2481 try {
2482 ms.removeSourceBuffer(sb);
2483 } catch (error) {
2484 _logger2.default.e(this.TAG, error.message);
2485 }
2486 sb.removeEventListener('error', this.e.onSourceBufferError);
2487 sb.removeEventListener('updateend', this.e.onSourceBufferUpdateEnd);
2488 }
2489 this._mimeTypes[type] = null;
2490 this._sourceBuffers[type] = null;
2491 }
2492 }
2493 if (ms.readyState === 'open') {
2494 try {
2495 ms.endOfStream();
2496 } catch (error) {
2497 _logger2.default.e(this.TAG, error.message);
2498 }
2499 }
2500 ms.removeEventListener('sourceopen', this.e.onSourceOpen);
2501 ms.removeEventListener('sourceended', this.e.onSourceEnded);
2502 ms.removeEventListener('sourceclose', this.e.onSourceClose);
2503 this._pendingSourceBufferInit = [];
2504 this._isBufferFull = false;
2505 this._idrList.clear();
2506 this._mediaSource = null;
2507 }
2508
2509 if (this._mediaElement) {
2510 this._mediaElement.src = '';
2511 this._mediaElement.removeAttribute('src');
2512 this._mediaElement = null;
2513 }
2514 if (this._mediaSourceObjectURL) {
2515 window.URL.revokeObjectURL(this._mediaSourceObjectURL);
2516 this._mediaSourceObjectURL = null;
2517 }
2518 }
2519 }, {
2520 key: 'appendInitSegment',
2521 value: function appendInitSegment(initSegment, deferred) {
2522 if (!this._mediaSource || this._mediaSource.readyState !== 'open') {
2523 // sourcebuffer creation requires mediaSource.readyState === 'open'
2524 // so we defer the sourcebuffer creation, until sourceopen event triggered
2525 this._pendingSourceBufferInit.push(initSegment);
2526 // make sure that this InitSegment is in the front of pending segments queue
2527 this._pendingSegments[initSegment.type].push(initSegment);
2528 return;
2529 }
2530
2531 var is = initSegment;
2532 var mimeType = '' + is.container;
2533 if (is.codec && is.codec.length > 0) {
2534 mimeType += ';codecs=' + is.codec;
2535 }
2536
2537 var firstInitSegment = false;
2538
2539 _logger2.default.v(this.TAG, 'Received Initialization Segment, mimeType: ' + mimeType);
2540 this._lastInitSegments[is.type] = is;
2541
2542 if (mimeType !== this._mimeTypes[is.type]) {
2543 if (!this._mimeTypes[is.type]) {
2544 // empty, first chance create sourcebuffer
2545 firstInitSegment = true;
2546 try {
2547 var sb = this._sourceBuffers[is.type] = this._mediaSource.addSourceBuffer(mimeType);
2548 sb.addEventListener('error', this.e.onSourceBufferError);
2549 sb.addEventListener('updateend', this.e.onSourceBufferUpdateEnd);
2550 } catch (error) {
2551 _logger2.default.e(this.TAG, error.message);
2552 this._emitter.emit(_mseEvents2.default.ERROR, { code: error.code, msg: error.message });
2553 return;
2554 }
2555 } else {
2556 _logger2.default.v(this.TAG, 'Notice: ' + is.type + ' mimeType changed, origin: ' + this._mimeTypes[is.type] + ', target: ' + mimeType);
2557 }
2558 this._mimeTypes[is.type] = mimeType;
2559 }
2560
2561 if (!deferred) {
2562 // deferred means this InitSegment has been pushed to pendingSegments queue
2563 this._pendingSegments[is.type].push(is);
2564 }
2565 if (!firstInitSegment) {
2566 // append immediately only if init segment in subsequence
2567 if (this._sourceBuffers[is.type] && !this._sourceBuffers[is.type].updating) {
2568 this._doAppendSegments();
2569 }
2570 }
2571 if (_browser2.default.safari && is.container === 'audio/mpeg' && is.mediaDuration > 0) {
2572 // 'audio/mpeg' track under Safari may cause MediaElement's duration to be NaN
2573 // Manually correct MediaSource.duration to make progress bar seekable, and report right duration
2574 this._requireSetMediaDuration = true;
2575 this._pendingMediaDuration = is.mediaDuration / 1000; // in seconds
2576 this._updateMediaSourceDuration();
2577 }
2578 }
2579 }, {
2580 key: 'appendMediaSegment',
2581 value: function appendMediaSegment(mediaSegment) {
2582 var ms = mediaSegment;
2583 this._pendingSegments[ms.type].push(ms);
2584
2585 if (this._config.autoCleanupSourceBuffer && this._needCleanupSourceBuffer()) {
2586 this._doCleanupSourceBuffer();
2587 }
2588
2589 var sb = this._sourceBuffers[ms.type];
2590 if (sb && !sb.updating && !this._hasPendingRemoveRanges()) {
2591 this._doAppendSegments();
2592 }
2593 }
2594 }, {
2595 key: 'seek',
2596 value: function seek(seconds) {
2597 // remove all appended buffers
2598 for (var type in this._sourceBuffers) {
2599 if (!this._sourceBuffers[type]) {
2600 continue;
2601 }
2602
2603 // abort current buffer append algorithm
2604 var sb = this._sourceBuffers[type];
2605 if (this._mediaSource.readyState === 'open') {
2606 try {
2607 // If range removal algorithm is running, InvalidStateError will be throwed
2608 // Ignore it.
2609 sb.abort();
2610 } catch (error) {
2611 _logger2.default.e(this.TAG, error.message);
2612 }
2613 }
2614
2615 // IDRList should be clear
2616 this._idrList.clear();
2617
2618 // pending segments should be discard
2619 var ps = this._pendingSegments[type];
2620 ps.splice(0, ps.length);
2621
2622 if (this._mediaSource.readyState === 'closed') {
2623 // Parent MediaSource object has been detached from HTMLMediaElement
2624 continue;
2625 }
2626
2627 // record ranges to be remove from SourceBuffer
2628 for (var i = 0; i < sb.buffered.length; i++) {
2629 var start = sb.buffered.start(i);
2630 var end = sb.buffered.end(i);
2631 this._pendingRemoveRanges[type].push({ start: start, end: end });
2632 }
2633
2634 // if sb is not updating, let's remove ranges now!
2635 if (!sb.updating) {
2636 this._doRemoveRanges();
2637 }
2638
2639 // Safari 10 may get InvalidStateError in the later appendBuffer() after SourceBuffer.remove() call
2640 // Internal parser's state may be invalid at this time. Re-append last InitSegment to workaround.
2641 // Related issue: https://bugs.webkit.org/show_bug.cgi?id=159230
2642 if (_browser2.default.safari) {
2643 var lastInitSegment = this._lastInitSegments[type];
2644 if (lastInitSegment) {
2645 this._pendingSegments[type].push(lastInitSegment);
2646 if (!sb.updating) {
2647 this._doAppendSegments();
2648 }
2649 }
2650 }
2651 }
2652 }
2653 }, {
2654 key: 'endOfStream',
2655 value: function endOfStream() {
2656 var ms = this._mediaSource;
2657 var sb = this._sourceBuffers;
2658 if (!ms || ms.readyState !== 'open') {
2659 if (ms && ms.readyState === 'closed' && this._hasPendingSegments()) {
2660 // If MediaSource hasn't turned into open state, and there're pending segments
2661 // Mark pending endOfStream, defer call until all pending segments appended complete
2662 this._hasPendingEos = true;
2663 }
2664 return;
2665 }
2666 if (sb.video && sb.video.updating || sb.audio && sb.audio.updating) {
2667 // If any sourcebuffer is updating, defer endOfStream operation
2668 // See _onSourceBufferUpdateEnd()
2669 this._hasPendingEos = true;
2670 } else {
2671 this._hasPendingEos = false;
2672 // Notify media data loading complete
2673 // This is helpful for correcting total duration to match last media segment
2674 // Otherwise MediaElement's ended event may not be triggered
2675 ms.endOfStream();
2676 }
2677 }
2678 }, {
2679 key: 'getNearestKeyframe',
2680 value: function getNearestKeyframe(dts) {
2681 return this._idrList.getLastSyncPointBeforeDts(dts);
2682 }
2683 }, {
2684 key: '_needCleanupSourceBuffer',
2685 value: function _needCleanupSourceBuffer() {
2686 if (!this._config.autoCleanupSourceBuffer) {
2687 return false;
2688 }
2689
2690 var currentTime = this._mediaElement.currentTime;
2691
2692 for (var type in this._sourceBuffers) {
2693 var sb = this._sourceBuffers[type];
2694 if (sb) {
2695 var buffered = sb.buffered;
2696 if (buffered.length >= 1) {
2697 if (currentTime - buffered.start(0) >= this._config.autoCleanupMaxBackwardDuration) {
2698 return true;
2699 }
2700 }
2701 }
2702 }
2703
2704 return false;
2705 }
2706 }, {
2707 key: '_doCleanupSourceBuffer',
2708 value: function _doCleanupSourceBuffer() {
2709 var currentTime = this._mediaElement.currentTime;
2710
2711 for (var type in this._sourceBuffers) {
2712 var sb = this._sourceBuffers[type];
2713 if (sb) {
2714 var buffered = sb.buffered;
2715 var doRemove = false;
2716
2717 for (var i = 0; i < buffered.length; i++) {
2718 var start = buffered.start(i);
2719 var end = buffered.end(i);
2720
2721 if (start <= currentTime && currentTime < end + 3) {
2722 // padding 3 seconds
2723 if (currentTime - start >= this._config.autoCleanupMaxBackwardDuration) {
2724 doRemove = true;
2725 var removeEnd = currentTime - this._config.autoCleanupMinBackwardDuration;
2726 this._pendingRemoveRanges[type].push({ start: start, end: removeEnd });
2727 }
2728 } else if (end < currentTime) {
2729 doRemove = true;
2730 this._pendingRemoveRanges[type].push({ start: start, end: end });
2731 }
2732 }
2733
2734 if (doRemove && !sb.updating) {
2735 this._doRemoveRanges();
2736 }
2737 }
2738 }
2739 }
2740 }, {
2741 key: '_updateMediaSourceDuration',
2742 value: function _updateMediaSourceDuration() {
2743 var sb = this._sourceBuffers;
2744 if (this._mediaElement.readyState === 0 || this._mediaSource.readyState !== 'open') {
2745 return;
2746 }
2747 if (sb.video && sb.video.updating || sb.audio && sb.audio.updating) {
2748 return;
2749 }
2750
2751 var current = this._mediaSource.duration;
2752 var target = this._pendingMediaDuration;
2753
2754 if (target > 0 && (isNaN(current) || target > current)) {
2755 _logger2.default.v(this.TAG, 'Update MediaSource duration from ' + current + ' to ' + target);
2756 this._mediaSource.duration = target;
2757 }
2758
2759 this._requireSetMediaDuration = false;
2760 this._pendingMediaDuration = 0;
2761 }
2762 }, {
2763 key: '_doRemoveRanges',
2764 value: function _doRemoveRanges() {
2765 for (var type in this._pendingRemoveRanges) {
2766 if (!this._sourceBuffers[type] || this._sourceBuffers[type].updating) {
2767 continue;
2768 }
2769 var sb = this._sourceBuffers[type];
2770 var ranges = this._pendingRemoveRanges[type];
2771 while (ranges.length && !sb.updating) {
2772 var range = ranges.shift();
2773 sb.remove(range.start, range.end);
2774 }
2775 }
2776 }
2777 }, {
2778 key: '_doAppendSegments',
2779 value: function _doAppendSegments() {
2780 var pendingSegments = this._pendingSegments;
2781
2782 for (var type in pendingSegments) {
2783 if (!this._sourceBuffers[type] || this._sourceBuffers[type].updating) {
2784 continue;
2785 }
2786
2787 if (pendingSegments[type].length > 0) {
2788 var segment = pendingSegments[type].shift();
2789
2790 if (segment.timestampOffset) {
2791 // For MPEG audio stream in MSE, if unbuffered-seeking occurred
2792 // We need explicitly set timestampOffset to the desired point in timeline for mpeg SourceBuffer.
2793 var currentOffset = this._sourceBuffers[type].timestampOffset;
2794 var targetOffset = segment.timestampOffset / 1000; // in seconds
2795
2796 var delta = Math.abs(currentOffset - targetOffset);
2797 if (delta > 0.1) {
2798 // If time delta > 100ms
2799 _logger2.default.v(this.TAG, 'Update MPEG audio timestampOffset from ' + currentOffset + ' to ' + targetOffset);
2800 this._sourceBuffers[type].timestampOffset = targetOffset;
2801 }
2802 delete segment.timestampOffset;
2803 }
2804
2805 if (!segment.data || segment.data.byteLength === 0) {
2806 // Ignore empty buffer
2807 continue;
2808 }
2809
2810 try {
2811 this._sourceBuffers[type].appendBuffer(segment.data);
2812 this._isBufferFull = false;
2813 if (type === 'video' && segment.hasOwnProperty('info')) {
2814 this._idrList.appendArray(segment.info.syncPoints);
2815 }
2816 } catch (error) {
2817 this._pendingSegments[type].unshift(segment);
2818 if (error.code === 22) {
2819 // QuotaExceededError
2820 /* Notice that FireFox may not throw QuotaExceededError if SourceBuffer is full
2821 * Currently we can only do lazy-load to avoid SourceBuffer become scattered.
2822 * SourceBuffer eviction policy may be changed in future version of FireFox.
2823 *
2824 * Related issues:
2825 * https://bugzilla.mozilla.org/show_bug.cgi?id=1279885
2826 * https://bugzilla.mozilla.org/show_bug.cgi?id=1280023
2827 */
2828
2829 // report buffer full, abort network IO
2830 if (!this._isBufferFull) {
2831 this._emitter.emit(_mseEvents2.default.BUFFER_FULL);
2832 }
2833 this._isBufferFull = true;
2834 } else {
2835 _logger2.default.e(this.TAG, error.message);
2836 this._emitter.emit(_mseEvents2.default.ERROR, { code: error.code, msg: error.message });
2837 }
2838 }
2839 }
2840 }
2841 }
2842 }, {
2843 key: '_onSourceOpen',
2844 value: function _onSourceOpen() {
2845 _logger2.default.v(this.TAG, 'MediaSource onSourceOpen');
2846 this._mediaSource.removeEventListener('sourceopen', this.e.onSourceOpen);
2847 // deferred sourcebuffer creation / initialization
2848 if (this._pendingSourceBufferInit.length > 0) {
2849 var pendings = this._pendingSourceBufferInit;
2850 while (pendings.length) {
2851 var segment = pendings.shift();
2852 this.appendInitSegment(segment, true);
2853 }
2854 }
2855 // there may be some pending media segments, append them
2856 if (this._hasPendingSegments()) {
2857 this._doAppendSegments();
2858 }
2859 this._emitter.emit(_mseEvents2.default.SOURCE_OPEN);
2860 }
2861 }, {
2862 key: '_onSourceEnded',
2863 value: function _onSourceEnded() {
2864 // fired on endOfStream
2865 _logger2.default.v(this.TAG, 'MediaSource onSourceEnded');
2866 }
2867 }, {
2868 key: '_onSourceClose',
2869 value: function _onSourceClose() {
2870 // fired on detaching from media element
2871 _logger2.default.v(this.TAG, 'MediaSource onSourceClose');
2872 if (this._mediaSource && this.e != null) {
2873 this._mediaSource.removeEventListener('sourceopen', this.e.onSourceOpen);
2874 this._mediaSource.removeEventListener('sourceended', this.e.onSourceEnded);
2875 this._mediaSource.removeEventListener('sourceclose', this.e.onSourceClose);
2876 }
2877 }
2878 }, {
2879 key: '_hasPendingSegments',
2880 value: function _hasPendingSegments() {
2881 var ps = this._pendingSegments;
2882 return ps.video.length > 0 || ps.audio.length > 0;
2883 }
2884 }, {
2885 key: '_hasPendingRemoveRanges',
2886 value: function _hasPendingRemoveRanges() {
2887 var prr = this._pendingRemoveRanges;
2888 return prr.video.length > 0 || prr.audio.length > 0;
2889 }
2890 }, {
2891 key: '_onSourceBufferUpdateEnd',
2892 value: function _onSourceBufferUpdateEnd() {
2893 if (this._requireSetMediaDuration) {
2894 this._updateMediaSourceDuration();
2895 } else if (this._hasPendingRemoveRanges()) {
2896 this._doRemoveRanges();
2897 } else if (this._hasPendingSegments()) {
2898 this._doAppendSegments();
2899 } else if (this._hasPendingEos) {
2900 this.endOfStream();
2901 }
2902 this._emitter.emit(_mseEvents2.default.UPDATE_END);
2903 }
2904 }, {
2905 key: '_onSourceBufferError',
2906 value: function _onSourceBufferError(e) {
2907 _logger2.default.e(this.TAG, 'SourceBuffer Error: ' + e);
2908 // this error might not always be fatal, just ignore it
2909 }
2910 }]);
2911
2912 return MSEController;
2913}();
2914
2915exports.default = MSEController;
2916
2917},{"../utils/browser.js":39,"../utils/exception.js":40,"../utils/logger.js":41,"./media-segment-info.js":8,"./mse-events.js":10,"events":2}],10:[function(_dereq_,module,exports){
2918'use strict';
2919
2920Object.defineProperty(exports, "__esModule", {
2921 value: true
2922});
2923/*
2924 * Copyright (C) 2016 Bilibili. All Rights Reserved.
2925 *
2926 * @author zheng qian <xqq@xqq.im>
2927 *
2928 * Licensed under the Apache License, Version 2.0 (the "License");
2929 * you may not use this file except in compliance with the License.
2930 * You may obtain a copy of the License at
2931 *
2932 * http://www.apache.org/licenses/LICENSE-2.0
2933 *
2934 * Unless required by applicable law or agreed to in writing, software
2935 * distributed under the License is distributed on an "AS IS" BASIS,
2936 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2937 * See the License for the specific language governing permissions and
2938 * limitations under the License.
2939 */
2940
2941var MSEEvents = {
2942 ERROR: 'error',
2943 SOURCE_OPEN: 'source_open',
2944 UPDATE_END: 'update_end',
2945 BUFFER_FULL: 'buffer_full'
2946};
2947
2948exports.default = MSEEvents;
2949
2950},{}],11:[function(_dereq_,module,exports){
2951'use strict';
2952
2953Object.defineProperty(exports, "__esModule", {
2954 value: true
2955});
2956
2957var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
2958 * Copyright (C) 2016 Bilibili. All Rights Reserved.
2959 *
2960 * @author zheng qian <xqq@xqq.im>
2961 *
2962 * Licensed under the Apache License, Version 2.0 (the "License");
2963 * you may not use this file except in compliance with the License.
2964 * You may obtain a copy of the License at
2965 *
2966 * http://www.apache.org/licenses/LICENSE-2.0
2967 *
2968 * Unless required by applicable law or agreed to in writing, software
2969 * distributed under the License is distributed on an "AS IS" BASIS,
2970 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2971 * See the License for the specific language governing permissions and
2972 * limitations under the License.
2973 */
2974
2975var _events = _dereq_('events');
2976
2977var _events2 = _interopRequireDefault(_events);
2978
2979var _logger = _dereq_('../utils/logger.js');
2980
2981var _logger2 = _interopRequireDefault(_logger);
2982
2983var _loggingControl = _dereq_('../utils/logging-control.js');
2984
2985var _loggingControl2 = _interopRequireDefault(_loggingControl);
2986
2987var _transmuxingController = _dereq_('./transmuxing-controller.js');
2988
2989var _transmuxingController2 = _interopRequireDefault(_transmuxingController);
2990
2991var _transmuxingEvents = _dereq_('./transmuxing-events.js');
2992
2993var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
2994
2995var _transmuxingWorker = _dereq_('./transmuxing-worker.js');
2996
2997var _transmuxingWorker2 = _interopRequireDefault(_transmuxingWorker);
2998
2999var _mediaInfo = _dereq_('./media-info.js');
3000
3001var _mediaInfo2 = _interopRequireDefault(_mediaInfo);
3002
3003function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
3004
3005function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3006
3007var Transmuxer = function () {
3008 function Transmuxer(mediaDataSource, config) {
3009 _classCallCheck(this, Transmuxer);
3010
3011 this.TAG = 'Transmuxer';
3012 this._emitter = new _events2.default();
3013
3014 if (config.enableWorker && typeof Worker !== 'undefined') {
3015 try {
3016 var work = _dereq_('webworkify');
3017 this._worker = work(_transmuxingWorker2.default);
3018 this._workerDestroying = false;
3019 this._worker.addEventListener('message', this._onWorkerMessage.bind(this));
3020 this._worker.postMessage({ cmd: 'init', param: [mediaDataSource, config] });
3021 this.e = {
3022 onLoggingConfigChanged: this._onLoggingConfigChanged.bind(this)
3023 };
3024 _loggingControl2.default.registerListener(this.e.onLoggingConfigChanged);
3025 this._worker.postMessage({ cmd: 'logging_config', param: _loggingControl2.default.getConfig() });
3026 } catch (error) {
3027 _logger2.default.e(this.TAG, 'Error while initialize transmuxing worker, fallback to inline transmuxing');
3028 this._worker = null;
3029 this._controller = new _transmuxingController2.default(mediaDataSource, config);
3030 }
3031 } else {
3032 this._controller = new _transmuxingController2.default(mediaDataSource, config);
3033 }
3034
3035 if (this._controller) {
3036 var ctl = this._controller;
3037 ctl.on(_transmuxingEvents2.default.IO_ERROR, this._onIOError.bind(this));
3038 ctl.on(_transmuxingEvents2.default.DEMUX_ERROR, this._onDemuxError.bind(this));
3039 ctl.on(_transmuxingEvents2.default.INIT_SEGMENT, this._onInitSegment.bind(this));
3040 ctl.on(_transmuxingEvents2.default.MEDIA_SEGMENT, this._onMediaSegment.bind(this));
3041 ctl.on(_transmuxingEvents2.default.LOADING_COMPLETE, this._onLoadingComplete.bind(this));
3042 ctl.on(_transmuxingEvents2.default.RECOVERED_EARLY_EOF, this._onRecoveredEarlyEof.bind(this));
3043 ctl.on(_transmuxingEvents2.default.MEDIA_INFO, this._onMediaInfo.bind(this));
3044 ctl.on(_transmuxingEvents2.default.METADATA_ARRIVED, this._onMetaDataArrived.bind(this));
3045 ctl.on(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, this._onScriptDataArrived.bind(this));
3046 ctl.on(_transmuxingEvents2.default.STATISTICS_INFO, this._onStatisticsInfo.bind(this));
3047 ctl.on(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, this._onRecommendSeekpoint.bind(this));
3048 }
3049 }
3050
3051 _createClass(Transmuxer, [{
3052 key: 'destroy',
3053 value: function destroy() {
3054 if (this._worker) {
3055 if (!this._workerDestroying) {
3056 this._workerDestroying = true;
3057 this._worker.postMessage({ cmd: 'destroy' });
3058 _loggingControl2.default.removeListener(this.e.onLoggingConfigChanged);
3059 this.e = null;
3060 }
3061 } else {
3062 this._controller.destroy();
3063 this._controller = null;
3064 }
3065 this._emitter.removeAllListeners();
3066 this._emitter = null;
3067 }
3068 }, {
3069 key: 'on',
3070 value: function on(event, listener) {
3071 this._emitter.addListener(event, listener);
3072 }
3073 }, {
3074 key: 'off',
3075 value: function off(event, listener) {
3076 this._emitter.removeListener(event, listener);
3077 }
3078 }, {
3079 key: 'hasWorker',
3080 value: function hasWorker() {
3081 return this._worker != null;
3082 }
3083 }, {
3084 key: 'open',
3085 value: function open() {
3086 if (this._worker) {
3087 this._worker.postMessage({ cmd: 'start' });
3088 } else {
3089 this._controller.start();
3090 }
3091 }
3092 }, {
3093 key: 'close',
3094 value: function close() {
3095 if (this._worker) {
3096 this._worker.postMessage({ cmd: 'stop' });
3097 } else {
3098 this._controller.stop();
3099 }
3100 }
3101 }, {
3102 key: 'seek',
3103 value: function seek(milliseconds) {
3104 if (this._worker) {
3105 this._worker.postMessage({ cmd: 'seek', param: milliseconds });
3106 } else {
3107 this._controller.seek(milliseconds);
3108 }
3109 }
3110 }, {
3111 key: 'pause',
3112 value: function pause() {
3113 if (this._worker) {
3114 this._worker.postMessage({ cmd: 'pause' });
3115 } else {
3116 this._controller.pause();
3117 }
3118 }
3119 }, {
3120 key: 'resume',
3121 value: function resume() {
3122 if (this._worker) {
3123 this._worker.postMessage({ cmd: 'resume' });
3124 } else {
3125 this._controller.resume();
3126 }
3127 }
3128 }, {
3129 key: '_onInitSegment',
3130 value: function _onInitSegment(type, initSegment) {
3131 var _this = this;
3132
3133 // do async invoke
3134 Promise.resolve().then(function () {
3135 _this._emitter.emit(_transmuxingEvents2.default.INIT_SEGMENT, type, initSegment);
3136 });
3137 }
3138 }, {
3139 key: '_onMediaSegment',
3140 value: function _onMediaSegment(type, mediaSegment) {
3141 var _this2 = this;
3142
3143 Promise.resolve().then(function () {
3144 _this2._emitter.emit(_transmuxingEvents2.default.MEDIA_SEGMENT, type, mediaSegment);
3145 });
3146 }
3147 }, {
3148 key: '_onLoadingComplete',
3149 value: function _onLoadingComplete() {
3150 var _this3 = this;
3151
3152 Promise.resolve().then(function () {
3153 _this3._emitter.emit(_transmuxingEvents2.default.LOADING_COMPLETE);
3154 });
3155 }
3156 }, {
3157 key: '_onRecoveredEarlyEof',
3158 value: function _onRecoveredEarlyEof() {
3159 var _this4 = this;
3160
3161 Promise.resolve().then(function () {
3162 _this4._emitter.emit(_transmuxingEvents2.default.RECOVERED_EARLY_EOF);
3163 });
3164 }
3165 }, {
3166 key: '_onMediaInfo',
3167 value: function _onMediaInfo(mediaInfo) {
3168 var _this5 = this;
3169
3170 Promise.resolve().then(function () {
3171 _this5._emitter.emit(_transmuxingEvents2.default.MEDIA_INFO, mediaInfo);
3172 });
3173 }
3174 }, {
3175 key: '_onMetaDataArrived',
3176 value: function _onMetaDataArrived(metadata) {
3177 var _this6 = this;
3178
3179 Promise.resolve().then(function () {
3180 _this6._emitter.emit(_transmuxingEvents2.default.METADATA_ARRIVED, metadata);
3181 });
3182 }
3183 }, {
3184 key: '_onScriptDataArrived',
3185 value: function _onScriptDataArrived(data) {
3186 var _this7 = this;
3187
3188 Promise.resolve().then(function () {
3189 _this7._emitter.emit(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, data);
3190 });
3191 }
3192 }, {
3193 key: '_onStatisticsInfo',
3194 value: function _onStatisticsInfo(statisticsInfo) {
3195 var _this8 = this;
3196
3197 Promise.resolve().then(function () {
3198 _this8._emitter.emit(_transmuxingEvents2.default.STATISTICS_INFO, statisticsInfo);
3199 });
3200 }
3201 }, {
3202 key: '_onIOError',
3203 value: function _onIOError(type, info) {
3204 var _this9 = this;
3205
3206 Promise.resolve().then(function () {
3207 _this9._emitter.emit(_transmuxingEvents2.default.IO_ERROR, type, info);
3208 });
3209 }
3210 }, {
3211 key: '_onDemuxError',
3212 value: function _onDemuxError(type, info) {
3213 var _this10 = this;
3214
3215 Promise.resolve().then(function () {
3216 _this10._emitter.emit(_transmuxingEvents2.default.DEMUX_ERROR, type, info);
3217 });
3218 }
3219 }, {
3220 key: '_onRecommendSeekpoint',
3221 value: function _onRecommendSeekpoint(milliseconds) {
3222 var _this11 = this;
3223
3224 Promise.resolve().then(function () {
3225 _this11._emitter.emit(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, milliseconds);
3226 });
3227 }
3228 }, {
3229 key: '_onLoggingConfigChanged',
3230 value: function _onLoggingConfigChanged(config) {
3231 if (this._worker) {
3232 this._worker.postMessage({ cmd: 'logging_config', param: config });
3233 }
3234 }
3235 }, {
3236 key: '_onWorkerMessage',
3237 value: function _onWorkerMessage(e) {
3238 var message = e.data;
3239 var data = message.data;
3240
3241 if (message.msg === 'destroyed' || this._workerDestroying) {
3242 this._workerDestroying = false;
3243 this._worker.terminate();
3244 this._worker = null;
3245 return;
3246 }
3247
3248 switch (message.msg) {
3249 case _transmuxingEvents2.default.INIT_SEGMENT:
3250 case _transmuxingEvents2.default.MEDIA_SEGMENT:
3251 this._emitter.emit(message.msg, data.type, data.data);
3252 break;
3253 case _transmuxingEvents2.default.LOADING_COMPLETE:
3254 case _transmuxingEvents2.default.RECOVERED_EARLY_EOF:
3255 this._emitter.emit(message.msg);
3256 break;
3257 case _transmuxingEvents2.default.MEDIA_INFO:
3258 Object.setPrototypeOf(data, _mediaInfo2.default.prototype);
3259 this._emitter.emit(message.msg, data);
3260 break;
3261 case _transmuxingEvents2.default.METADATA_ARRIVED:
3262 case _transmuxingEvents2.default.SCRIPTDATA_ARRIVED:
3263 case _transmuxingEvents2.default.STATISTICS_INFO:
3264 this._emitter.emit(message.msg, data);
3265 break;
3266 case _transmuxingEvents2.default.IO_ERROR:
3267 case _transmuxingEvents2.default.DEMUX_ERROR:
3268 this._emitter.emit(message.msg, data.type, data.info);
3269 break;
3270 case _transmuxingEvents2.default.RECOMMEND_SEEKPOINT:
3271 this._emitter.emit(message.msg, data);
3272 break;
3273 case 'logcat_callback':
3274 _logger2.default.emitter.emit('log', data.type, data.logcat);
3275 break;
3276 default:
3277 break;
3278 }
3279 }
3280 }]);
3281
3282 return Transmuxer;
3283}();
3284
3285exports.default = Transmuxer;
3286
3287},{"../utils/logger.js":41,"../utils/logging-control.js":42,"./media-info.js":7,"./transmuxing-controller.js":12,"./transmuxing-events.js":13,"./transmuxing-worker.js":14,"events":2,"webworkify":4}],12:[function(_dereq_,module,exports){
3288'use strict';
3289
3290Object.defineProperty(exports, "__esModule", {
3291 value: true
3292});
3293
3294var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
3295 * Copyright (C) 2016 Bilibili. All Rights Reserved.
3296 *
3297 * @author zheng qian <xqq@xqq.im>
3298 *
3299 * Licensed under the Apache License, Version 2.0 (the "License");
3300 * you may not use this file except in compliance with the License.
3301 * You may obtain a copy of the License at
3302 *
3303 * http://www.apache.org/licenses/LICENSE-2.0
3304 *
3305 * Unless required by applicable law or agreed to in writing, software
3306 * distributed under the License is distributed on an "AS IS" BASIS,
3307 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3308 * See the License for the specific language governing permissions and
3309 * limitations under the License.
3310 */
3311
3312var _events = _dereq_('events');
3313
3314var _events2 = _interopRequireDefault(_events);
3315
3316var _logger = _dereq_('../utils/logger.js');
3317
3318var _logger2 = _interopRequireDefault(_logger);
3319
3320var _browser = _dereq_('../utils/browser.js');
3321
3322var _browser2 = _interopRequireDefault(_browser);
3323
3324var _mediaInfo = _dereq_('./media-info.js');
3325
3326var _mediaInfo2 = _interopRequireDefault(_mediaInfo);
3327
3328var _flvDemuxer = _dereq_('../demux/flv-demuxer.js');
3329
3330var _flvDemuxer2 = _interopRequireDefault(_flvDemuxer);
3331
3332var _mp4Remuxer = _dereq_('../remux/mp4-remuxer.js');
3333
3334var _mp4Remuxer2 = _interopRequireDefault(_mp4Remuxer);
3335
3336var _demuxErrors = _dereq_('../demux/demux-errors.js');
3337
3338var _demuxErrors2 = _interopRequireDefault(_demuxErrors);
3339
3340var _ioController = _dereq_('../io/io-controller.js');
3341
3342var _ioController2 = _interopRequireDefault(_ioController);
3343
3344var _transmuxingEvents = _dereq_('./transmuxing-events.js');
3345
3346var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
3347
3348var _loader = _dereq_('../io/loader.js');
3349
3350function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
3351
3352function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3353
3354// Transmuxing (IO, Demuxing, Remuxing) controller, with multipart support
3355var TransmuxingController = function () {
3356 function TransmuxingController(mediaDataSource, config) {
3357 _classCallCheck(this, TransmuxingController);
3358
3359 this.TAG = 'TransmuxingController';
3360 this._emitter = new _events2.default();
3361
3362 this._config = config;
3363
3364 // treat single part media as multipart media, which has only one segment
3365 if (!mediaDataSource.segments) {
3366 mediaDataSource.segments = [{
3367 duration: mediaDataSource.duration,
3368 filesize: mediaDataSource.filesize,
3369 url: mediaDataSource.url
3370 }];
3371 }
3372
3373 // fill in default IO params if not exists
3374 if (typeof mediaDataSource.cors !== 'boolean') {
3375 mediaDataSource.cors = true;
3376 }
3377 if (typeof mediaDataSource.withCredentials !== 'boolean') {
3378 mediaDataSource.withCredentials = false;
3379 }
3380
3381 this._mediaDataSource = mediaDataSource;
3382 this._currentSegmentIndex = 0;
3383 var totalDuration = 0;
3384
3385 this._mediaDataSource.segments.forEach(function (segment) {
3386 // timestampBase for each segment, and calculate total duration
3387 segment.timestampBase = totalDuration;
3388 totalDuration += segment.duration;
3389 // params needed by IOController
3390 segment.cors = mediaDataSource.cors;
3391 segment.withCredentials = mediaDataSource.withCredentials;
3392 // referrer policy control, if exist
3393 if (config.referrerPolicy) {
3394 segment.referrerPolicy = config.referrerPolicy;
3395 }
3396 });
3397
3398 if (!isNaN(totalDuration) && this._mediaDataSource.duration !== totalDuration) {
3399 this._mediaDataSource.duration = totalDuration;
3400 }
3401
3402 this._mediaInfo = null;
3403 this._demuxer = null;
3404 this._remuxer = null;
3405 this._ioctl = null;
3406
3407 this._pendingSeekTime = null;
3408 this._pendingResolveSeekPoint = null;
3409
3410 this._statisticsReporter = null;
3411 }
3412
3413 _createClass(TransmuxingController, [{
3414 key: 'destroy',
3415 value: function destroy() {
3416 this._mediaInfo = null;
3417 this._mediaDataSource = null;
3418
3419 if (this._statisticsReporter) {
3420 this._disableStatisticsReporter();
3421 }
3422 if (this._ioctl) {
3423 this._ioctl.destroy();
3424 this._ioctl = null;
3425 }
3426 if (this._demuxer) {
3427 this._demuxer.destroy();
3428 this._demuxer = null;
3429 }
3430 if (this._remuxer) {
3431 this._remuxer.destroy();
3432 this._remuxer = null;
3433 }
3434
3435 this._emitter.removeAllListeners();
3436 this._emitter = null;
3437 }
3438 }, {
3439 key: 'on',
3440 value: function on(event, listener) {
3441 this._emitter.addListener(event, listener);
3442 }
3443 }, {
3444 key: 'off',
3445 value: function off(event, listener) {
3446 this._emitter.removeListener(event, listener);
3447 }
3448 }, {
3449 key: 'start',
3450 value: function start() {
3451 this._loadSegment(0);
3452 this._enableStatisticsReporter();
3453 }
3454 }, {
3455 key: '_loadSegment',
3456 value: function _loadSegment(segmentIndex, optionalFrom) {
3457 this._currentSegmentIndex = segmentIndex;
3458 var dataSource = this._mediaDataSource.segments[segmentIndex];
3459
3460 var ioctl = this._ioctl = new _ioController2.default(dataSource, this._config, segmentIndex);
3461 ioctl.onError = this._onIOException.bind(this);
3462 ioctl.onSeeked = this._onIOSeeked.bind(this);
3463 ioctl.onComplete = this._onIOComplete.bind(this);
3464 ioctl.onRedirect = this._onIORedirect.bind(this);
3465 ioctl.onRecoveredEarlyEof = this._onIORecoveredEarlyEof.bind(this);
3466
3467 if (optionalFrom) {
3468 this._demuxer.bindDataSource(this._ioctl);
3469 } else {
3470 ioctl.onDataArrival = this._onInitChunkArrival.bind(this);
3471 }
3472
3473 ioctl.open(optionalFrom);
3474 }
3475 }, {
3476 key: 'stop',
3477 value: function stop() {
3478 this._internalAbort();
3479 this._disableStatisticsReporter();
3480 }
3481 }, {
3482 key: '_internalAbort',
3483 value: function _internalAbort() {
3484 if (this._ioctl) {
3485 this._ioctl.destroy();
3486 this._ioctl = null;
3487 }
3488 }
3489 }, {
3490 key: 'pause',
3491 value: function pause() {
3492 // take a rest
3493 if (this._ioctl && this._ioctl.isWorking()) {
3494 this._ioctl.pause();
3495 this._disableStatisticsReporter();
3496 }
3497 }
3498 }, {
3499 key: 'resume',
3500 value: function resume() {
3501 if (this._ioctl && this._ioctl.isPaused()) {
3502 this._ioctl.resume();
3503 this._enableStatisticsReporter();
3504 }
3505 }
3506 }, {
3507 key: 'seek',
3508 value: function seek(milliseconds) {
3509 if (this._mediaInfo == null || !this._mediaInfo.isSeekable()) {
3510 return;
3511 }
3512
3513 var targetSegmentIndex = this._searchSegmentIndexContains(milliseconds);
3514
3515 if (targetSegmentIndex === this._currentSegmentIndex) {
3516 // intra-segment seeking
3517 var segmentInfo = this._mediaInfo.segments[targetSegmentIndex];
3518
3519 if (segmentInfo == undefined) {
3520 // current segment loading started, but mediainfo hasn't received yet
3521 // wait for the metadata loaded, then seek to expected position
3522 this._pendingSeekTime = milliseconds;
3523 } else {
3524 var keyframe = segmentInfo.getNearestKeyframe(milliseconds);
3525 this._remuxer.seek(keyframe.milliseconds);
3526 this._ioctl.seek(keyframe.fileposition);
3527 // Will be resolved in _onRemuxerMediaSegmentArrival()
3528 this._pendingResolveSeekPoint = keyframe.milliseconds;
3529 }
3530 } else {
3531 // cross-segment seeking
3532 var targetSegmentInfo = this._mediaInfo.segments[targetSegmentIndex];
3533
3534 if (targetSegmentInfo == undefined) {
3535 // target segment hasn't been loaded. We need metadata then seek to expected time
3536 this._pendingSeekTime = milliseconds;
3537 this._internalAbort();
3538 this._remuxer.seek();
3539 this._remuxer.insertDiscontinuity();
3540 this._loadSegment(targetSegmentIndex);
3541 // Here we wait for the metadata loaded, then seek to expected position
3542 } else {
3543 // We have target segment's metadata, direct seek to target position
3544 var _keyframe = targetSegmentInfo.getNearestKeyframe(milliseconds);
3545 this._internalAbort();
3546 this._remuxer.seek(milliseconds);
3547 this._remuxer.insertDiscontinuity();
3548 this._demuxer.resetMediaInfo();
3549 this._demuxer.timestampBase = this._mediaDataSource.segments[targetSegmentIndex].timestampBase;
3550 this._loadSegment(targetSegmentIndex, _keyframe.fileposition);
3551 this._pendingResolveSeekPoint = _keyframe.milliseconds;
3552 this._reportSegmentMediaInfo(targetSegmentIndex);
3553 }
3554 }
3555
3556 this._enableStatisticsReporter();
3557 }
3558 }, {
3559 key: '_searchSegmentIndexContains',
3560 value: function _searchSegmentIndexContains(milliseconds) {
3561 var segments = this._mediaDataSource.segments;
3562 var idx = segments.length - 1;
3563
3564 for (var i = 0; i < segments.length; i++) {
3565 if (milliseconds < segments[i].timestampBase) {
3566 idx = i - 1;
3567 break;
3568 }
3569 }
3570 return idx;
3571 }
3572 }, {
3573 key: '_onInitChunkArrival',
3574 value: function _onInitChunkArrival(data, byteStart) {
3575 var _this = this;
3576
3577 var probeData = null;
3578 var consumed = 0;
3579
3580 if (byteStart > 0) {
3581 // IOController seeked immediately after opened, byteStart > 0 callback may received
3582 this._demuxer.bindDataSource(this._ioctl);
3583 this._demuxer.timestampBase = this._mediaDataSource.segments[this._currentSegmentIndex].timestampBase;
3584
3585 consumed = this._demuxer.parseChunks(data, byteStart);
3586 } else if ((probeData = _flvDemuxer2.default.probe(data)).match) {
3587 // Always create new FLVDemuxer
3588 this._demuxer = new _flvDemuxer2.default(probeData, this._config);
3589
3590 if (!this._remuxer) {
3591 this._remuxer = new _mp4Remuxer2.default(this._config);
3592 }
3593
3594 var mds = this._mediaDataSource;
3595 if (mds.duration != undefined && !isNaN(mds.duration)) {
3596 this._demuxer.overridedDuration = mds.duration;
3597 }
3598 if (typeof mds.hasAudio === 'boolean') {
3599 this._demuxer.overridedHasAudio = mds.hasAudio;
3600 }
3601 if (typeof mds.hasVideo === 'boolean') {
3602 this._demuxer.overridedHasVideo = mds.hasVideo;
3603 }
3604
3605 this._demuxer.timestampBase = mds.segments[this._currentSegmentIndex].timestampBase;
3606
3607 this._demuxer.onError = this._onDemuxException.bind(this);
3608 this._demuxer.onMediaInfo = this._onMediaInfo.bind(this);
3609 this._demuxer.onMetaDataArrived = this._onMetaDataArrived.bind(this);
3610 this._demuxer.onScriptDataArrived = this._onScriptDataArrived.bind(this);
3611
3612 this._remuxer.bindDataSource(this._demuxer.bindDataSource(this._ioctl));
3613
3614 this._remuxer.onInitSegment = this._onRemuxerInitSegmentArrival.bind(this);
3615 this._remuxer.onMediaSegment = this._onRemuxerMediaSegmentArrival.bind(this);
3616
3617 consumed = this._demuxer.parseChunks(data, byteStart);
3618 } else {
3619 probeData = null;
3620 _logger2.default.e(this.TAG, 'Non-FLV, Unsupported media type!');
3621 Promise.resolve().then(function () {
3622 _this._internalAbort();
3623 });
3624 this._emitter.emit(_transmuxingEvents2.default.DEMUX_ERROR, _demuxErrors2.default.FORMAT_UNSUPPORTED, 'Non-FLV, Unsupported media type');
3625
3626 consumed = 0;
3627 }
3628
3629 return consumed;
3630 }
3631 }, {
3632 key: '_onMediaInfo',
3633 value: function _onMediaInfo(mediaInfo) {
3634 var _this2 = this;
3635
3636 if (this._mediaInfo == null) {
3637 // Store first segment's mediainfo as global mediaInfo
3638 this._mediaInfo = Object.assign({}, mediaInfo);
3639 this._mediaInfo.keyframesIndex = null;
3640 this._mediaInfo.segments = [];
3641 this._mediaInfo.segmentCount = this._mediaDataSource.segments.length;
3642 Object.setPrototypeOf(this._mediaInfo, _mediaInfo2.default.prototype);
3643 }
3644
3645 var segmentInfo = Object.assign({}, mediaInfo);
3646 Object.setPrototypeOf(segmentInfo, _mediaInfo2.default.prototype);
3647 this._mediaInfo.segments[this._currentSegmentIndex] = segmentInfo;
3648
3649 // notify mediaInfo update
3650 this._reportSegmentMediaInfo(this._currentSegmentIndex);
3651
3652 if (this._pendingSeekTime != null) {
3653 Promise.resolve().then(function () {
3654 var target = _this2._pendingSeekTime;
3655 _this2._pendingSeekTime = null;
3656 _this2.seek(target);
3657 });
3658 }
3659 }
3660 }, {
3661 key: '_onMetaDataArrived',
3662 value: function _onMetaDataArrived(metadata) {
3663 this._emitter.emit(_transmuxingEvents2.default.METADATA_ARRIVED, metadata);
3664 }
3665 }, {
3666 key: '_onScriptDataArrived',
3667 value: function _onScriptDataArrived(data) {
3668 this._emitter.emit(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, data);
3669 }
3670 }, {
3671 key: '_onIOSeeked',
3672 value: function _onIOSeeked() {
3673 this._remuxer.insertDiscontinuity();
3674 }
3675 }, {
3676 key: '_onIOComplete',
3677 value: function _onIOComplete(extraData) {
3678 var segmentIndex = extraData;
3679 var nextSegmentIndex = segmentIndex + 1;
3680
3681 if (nextSegmentIndex < this._mediaDataSource.segments.length) {
3682 this._internalAbort();
3683 this._remuxer.flushStashedSamples();
3684 this._loadSegment(nextSegmentIndex);
3685 } else {
3686 this._remuxer.flushStashedSamples();
3687 this._emitter.emit(_transmuxingEvents2.default.LOADING_COMPLETE);
3688 this._disableStatisticsReporter();
3689 }
3690 }
3691 }, {
3692 key: '_onIORedirect',
3693 value: function _onIORedirect(redirectedURL) {
3694 var segmentIndex = this._ioctl.extraData;
3695 this._mediaDataSource.segments[segmentIndex].redirectedURL = redirectedURL;
3696 }
3697 }, {
3698 key: '_onIORecoveredEarlyEof',
3699 value: function _onIORecoveredEarlyEof() {
3700 this._emitter.emit(_transmuxingEvents2.default.RECOVERED_EARLY_EOF);
3701 }
3702 }, {
3703 key: '_onIOException',
3704 value: function _onIOException(type, info) {
3705 _logger2.default.e(this.TAG, 'IOException: type = ' + type + ', code = ' + info.code + ', msg = ' + info.msg);
3706 this._emitter.emit(_transmuxingEvents2.default.IO_ERROR, type, info);
3707 this._disableStatisticsReporter();
3708 }
3709 }, {
3710 key: '_onDemuxException',
3711 value: function _onDemuxException(type, info) {
3712 _logger2.default.e(this.TAG, 'DemuxException: type = ' + type + ', info = ' + info);
3713 this._emitter.emit(_transmuxingEvents2.default.DEMUX_ERROR, type, info);
3714 }
3715 }, {
3716 key: '_onRemuxerInitSegmentArrival',
3717 value: function _onRemuxerInitSegmentArrival(type, initSegment) {
3718 this._emitter.emit(_transmuxingEvents2.default.INIT_SEGMENT, type, initSegment);
3719 }
3720 }, {
3721 key: '_onRemuxerMediaSegmentArrival',
3722 value: function _onRemuxerMediaSegmentArrival(type, mediaSegment) {
3723 if (this._pendingSeekTime != null) {
3724 // Media segments after new-segment cross-seeking should be dropped.
3725 return;
3726 }
3727 this._emitter.emit(_transmuxingEvents2.default.MEDIA_SEGMENT, type, mediaSegment);
3728
3729 // Resolve pending seekPoint
3730 if (this._pendingResolveSeekPoint != null && type === 'video') {
3731 var syncPoints = mediaSegment.info.syncPoints;
3732 var seekpoint = this._pendingResolveSeekPoint;
3733 this._pendingResolveSeekPoint = null;
3734
3735 // Safari: Pass PTS for recommend_seekpoint
3736 if (_browser2.default.safari && syncPoints.length > 0 && syncPoints[0].originalDts === seekpoint) {
3737 seekpoint = syncPoints[0].pts;
3738 }
3739 // else: use original DTS (keyframe.milliseconds)
3740
3741 this._emitter.emit(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, seekpoint);
3742 }
3743 }
3744 }, {
3745 key: '_enableStatisticsReporter',
3746 value: function _enableStatisticsReporter() {
3747 if (this._statisticsReporter == null) {
3748 this._statisticsReporter = self.setInterval(this._reportStatisticsInfo.bind(this), this._config.statisticsInfoReportInterval);
3749 }
3750 }
3751 }, {
3752 key: '_disableStatisticsReporter',
3753 value: function _disableStatisticsReporter() {
3754 if (this._statisticsReporter) {
3755 self.clearInterval(this._statisticsReporter);
3756 this._statisticsReporter = null;
3757 }
3758 }
3759 }, {
3760 key: '_reportSegmentMediaInfo',
3761 value: function _reportSegmentMediaInfo(segmentIndex) {
3762 var segmentInfo = this._mediaInfo.segments[segmentIndex];
3763 var exportInfo = Object.assign({}, segmentInfo);
3764
3765 exportInfo.duration = this._mediaInfo.duration;
3766 exportInfo.segmentCount = this._mediaInfo.segmentCount;
3767 delete exportInfo.segments;
3768 delete exportInfo.keyframesIndex;
3769
3770 this._emitter.emit(_transmuxingEvents2.default.MEDIA_INFO, exportInfo);
3771 }
3772 }, {
3773 key: '_reportStatisticsInfo',
3774 value: function _reportStatisticsInfo() {
3775 var info = {};
3776
3777 info.url = this._ioctl.currentURL;
3778 info.hasRedirect = this._ioctl.hasRedirect;
3779 if (info.hasRedirect) {
3780 info.redirectedURL = this._ioctl.currentRedirectedURL;
3781 }
3782
3783 info.speed = this._ioctl.currentSpeed;
3784 info.loaderType = this._ioctl.loaderType;
3785 info.currentSegmentIndex = this._currentSegmentIndex;
3786 info.totalSegmentCount = this._mediaDataSource.segments.length;
3787
3788 this._emitter.emit(_transmuxingEvents2.default.STATISTICS_INFO, info);
3789 }
3790 }]);
3791
3792 return TransmuxingController;
3793}();
3794
3795exports.default = TransmuxingController;
3796
3797},{"../demux/demux-errors.js":16,"../demux/flv-demuxer.js":18,"../io/io-controller.js":23,"../io/loader.js":24,"../remux/mp4-remuxer.js":38,"../utils/browser.js":39,"../utils/logger.js":41,"./media-info.js":7,"./transmuxing-events.js":13,"events":2}],13:[function(_dereq_,module,exports){
3798'use strict';
3799
3800Object.defineProperty(exports, "__esModule", {
3801 value: true
3802});
3803/*
3804 * Copyright (C) 2016 Bilibili. All Rights Reserved.
3805 *
3806 * @author zheng qian <xqq@xqq.im>
3807 *
3808 * Licensed under the Apache License, Version 2.0 (the "License");
3809 * you may not use this file except in compliance with the License.
3810 * You may obtain a copy of the License at
3811 *
3812 * http://www.apache.org/licenses/LICENSE-2.0
3813 *
3814 * Unless required by applicable law or agreed to in writing, software
3815 * distributed under the License is distributed on an "AS IS" BASIS,
3816 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3817 * See the License for the specific language governing permissions and
3818 * limitations under the License.
3819 */
3820
3821var TransmuxingEvents = {
3822 IO_ERROR: 'io_error',
3823 DEMUX_ERROR: 'demux_error',
3824 INIT_SEGMENT: 'init_segment',
3825 MEDIA_SEGMENT: 'media_segment',
3826 LOADING_COMPLETE: 'loading_complete',
3827 RECOVERED_EARLY_EOF: 'recovered_early_eof',
3828 MEDIA_INFO: 'media_info',
3829 METADATA_ARRIVED: 'metadata_arrived',
3830 SCRIPTDATA_ARRIVED: 'scriptdata_arrived',
3831 STATISTICS_INFO: 'statistics_info',
3832 RECOMMEND_SEEKPOINT: 'recommend_seekpoint'
3833};
3834
3835exports.default = TransmuxingEvents;
3836
3837},{}],14:[function(_dereq_,module,exports){
3838'use strict';
3839
3840Object.defineProperty(exports, "__esModule", {
3841 value: true
3842});
3843
3844var _logger = _dereq_('../utils/logger.js');
3845
3846var _logger2 = _interopRequireDefault(_logger);
3847
3848var _loggingControl = _dereq_('../utils/logging-control.js');
3849
3850var _loggingControl2 = _interopRequireDefault(_loggingControl);
3851
3852var _polyfill = _dereq_('../utils/polyfill.js');
3853
3854var _polyfill2 = _interopRequireDefault(_polyfill);
3855
3856var _transmuxingController = _dereq_('./transmuxing-controller.js');
3857
3858var _transmuxingController2 = _interopRequireDefault(_transmuxingController);
3859
3860var _transmuxingEvents = _dereq_('./transmuxing-events.js');
3861
3862var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
3863
3864function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
3865
3866/* post message to worker:
3867 data: {
3868 cmd: string
3869 param: any
3870 }
3871
3872 receive message from worker:
3873 data: {
3874 msg: string,
3875 data: any
3876 }
3877 */
3878
3879var TransmuxingWorker = function TransmuxingWorker(self) {
3880
3881 var TAG = 'TransmuxingWorker';
3882 var controller = null;
3883 var logcatListener = onLogcatCallback.bind(this);
3884
3885 _polyfill2.default.install();
3886
3887 self.addEventListener('message', function (e) {
3888 switch (e.data.cmd) {
3889 case 'init':
3890 controller = new _transmuxingController2.default(e.data.param[0], e.data.param[1]);
3891 controller.on(_transmuxingEvents2.default.IO_ERROR, onIOError.bind(this));
3892 controller.on(_transmuxingEvents2.default.DEMUX_ERROR, onDemuxError.bind(this));
3893 controller.on(_transmuxingEvents2.default.INIT_SEGMENT, onInitSegment.bind(this));
3894 controller.on(_transmuxingEvents2.default.MEDIA_SEGMENT, onMediaSegment.bind(this));
3895 controller.on(_transmuxingEvents2.default.LOADING_COMPLETE, onLoadingComplete.bind(this));
3896 controller.on(_transmuxingEvents2.default.RECOVERED_EARLY_EOF, onRecoveredEarlyEof.bind(this));
3897 controller.on(_transmuxingEvents2.default.MEDIA_INFO, onMediaInfo.bind(this));
3898 controller.on(_transmuxingEvents2.default.METADATA_ARRIVED, onMetaDataArrived.bind(this));
3899 controller.on(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, onScriptDataArrived.bind(this));
3900 controller.on(_transmuxingEvents2.default.STATISTICS_INFO, onStatisticsInfo.bind(this));
3901 controller.on(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, onRecommendSeekpoint.bind(this));
3902 break;
3903 case 'destroy':
3904 if (controller) {
3905 controller.destroy();
3906 controller = null;
3907 }
3908 self.postMessage({ msg: 'destroyed' });
3909 break;
3910 case 'start':
3911 controller.start();
3912 break;
3913 case 'stop':
3914 controller.stop();
3915 break;
3916 case 'seek':
3917 controller.seek(e.data.param);
3918 break;
3919 case 'pause':
3920 controller.pause();
3921 break;
3922 case 'resume':
3923 controller.resume();
3924 break;
3925 case 'logging_config':
3926 {
3927 var config = e.data.param;
3928 _loggingControl2.default.applyConfig(config);
3929
3930 if (config.enableCallback === true) {
3931 _loggingControl2.default.addLogListener(logcatListener);
3932 } else {
3933 _loggingControl2.default.removeLogListener(logcatListener);
3934 }
3935 break;
3936 }
3937 }
3938 });
3939
3940 function onInitSegment(type, initSegment) {
3941 var obj = {
3942 msg: _transmuxingEvents2.default.INIT_SEGMENT,
3943 data: {
3944 type: type,
3945 data: initSegment
3946 }
3947 };
3948 self.postMessage(obj, [initSegment.data]); // data: ArrayBuffer
3949 }
3950
3951 function onMediaSegment(type, mediaSegment) {
3952 var obj = {
3953 msg: _transmuxingEvents2.default.MEDIA_SEGMENT,
3954 data: {
3955 type: type,
3956 data: mediaSegment
3957 }
3958 };
3959 self.postMessage(obj, [mediaSegment.data]); // data: ArrayBuffer
3960 }
3961
3962 function onLoadingComplete() {
3963 var obj = {
3964 msg: _transmuxingEvents2.default.LOADING_COMPLETE
3965 };
3966 self.postMessage(obj);
3967 }
3968
3969 function onRecoveredEarlyEof() {
3970 var obj = {
3971 msg: _transmuxingEvents2.default.RECOVERED_EARLY_EOF
3972 };
3973 self.postMessage(obj);
3974 }
3975
3976 function onMediaInfo(mediaInfo) {
3977 var obj = {
3978 msg: _transmuxingEvents2.default.MEDIA_INFO,
3979 data: mediaInfo
3980 };
3981 self.postMessage(obj);
3982 }
3983
3984 function onMetaDataArrived(metadata) {
3985 var obj = {
3986 msg: _transmuxingEvents2.default.METADATA_ARRIVED,
3987 data: metadata
3988 };
3989 self.postMessage(obj);
3990 }
3991
3992 function onScriptDataArrived(data) {
3993 var obj = {
3994 msg: _transmuxingEvents2.default.SCRIPTDATA_ARRIVED,
3995 data: data
3996 };
3997 self.postMessage(obj);
3998 }
3999
4000 function onStatisticsInfo(statInfo) {
4001 var obj = {
4002 msg: _transmuxingEvents2.default.STATISTICS_INFO,
4003 data: statInfo
4004 };
4005 self.postMessage(obj);
4006 }
4007
4008 function onIOError(type, info) {
4009 self.postMessage({
4010 msg: _transmuxingEvents2.default.IO_ERROR,
4011 data: {
4012 type: type,
4013 info: info
4014 }
4015 });
4016 }
4017
4018 function onDemuxError(type, info) {
4019 self.postMessage({
4020 msg: _transmuxingEvents2.default.DEMUX_ERROR,
4021 data: {
4022 type: type,
4023 info: info
4024 }
4025 });
4026 }
4027
4028 function onRecommendSeekpoint(milliseconds) {
4029 self.postMessage({
4030 msg: _transmuxingEvents2.default.RECOMMEND_SEEKPOINT,
4031 data: milliseconds
4032 });
4033 }
4034
4035 function onLogcatCallback(type, str) {
4036 self.postMessage({
4037 msg: 'logcat_callback',
4038 data: {
4039 type: type,
4040 logcat: str
4041 }
4042 });
4043 }
4044}; /*
4045 * Copyright (C) 2016 Bilibili. All Rights Reserved.
4046 *
4047 * @author zheng qian <xqq@xqq.im>
4048 *
4049 * Licensed under the Apache License, Version 2.0 (the "License");
4050 * you may not use this file except in compliance with the License.
4051 * You may obtain a copy of the License at
4052 *
4053 * http://www.apache.org/licenses/LICENSE-2.0
4054 *
4055 * Unless required by applicable law or agreed to in writing, software
4056 * distributed under the License is distributed on an "AS IS" BASIS,
4057 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4058 * See the License for the specific language governing permissions and
4059 * limitations under the License.
4060 */
4061
4062exports.default = TransmuxingWorker;
4063
4064},{"../utils/logger.js":41,"../utils/logging-control.js":42,"../utils/polyfill.js":43,"./transmuxing-controller.js":12,"./transmuxing-events.js":13}],15:[function(_dereq_,module,exports){
4065'use strict';
4066
4067Object.defineProperty(exports, "__esModule", {
4068 value: true
4069});
4070
4071var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
4072 * Copyright (C) 2016 Bilibili. All Rights Reserved.
4073 *
4074 * @author zheng qian <xqq@xqq.im>
4075 *
4076 * Licensed under the Apache License, Version 2.0 (the "License");
4077 * you may not use this file except in compliance with the License.
4078 * You may obtain a copy of the License at
4079 *
4080 * http://www.apache.org/licenses/LICENSE-2.0
4081 *
4082 * Unless required by applicable law or agreed to in writing, software
4083 * distributed under the License is distributed on an "AS IS" BASIS,
4084 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4085 * See the License for the specific language governing permissions and
4086 * limitations under the License.
4087 */
4088
4089var _logger = _dereq_('../utils/logger.js');
4090
4091var _logger2 = _interopRequireDefault(_logger);
4092
4093var _utf8Conv = _dereq_('../utils/utf8-conv.js');
4094
4095var _utf8Conv2 = _interopRequireDefault(_utf8Conv);
4096
4097var _exception = _dereq_('../utils/exception.js');
4098
4099function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
4100
4101function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4102
4103var le = function () {
4104 var buf = new ArrayBuffer(2);
4105 new DataView(buf).setInt16(0, 256, true); // little-endian write
4106 return new Int16Array(buf)[0] === 256; // platform-spec read, if equal then LE
4107}();
4108
4109var AMF = function () {
4110 function AMF() {
4111 _classCallCheck(this, AMF);
4112 }
4113
4114 _createClass(AMF, null, [{
4115 key: 'parseScriptData',
4116 value: function parseScriptData(arrayBuffer, dataOffset, dataSize) {
4117 var data = {};
4118
4119 try {
4120 var name = AMF.parseValue(arrayBuffer, dataOffset, dataSize);
4121 var value = AMF.parseValue(arrayBuffer, dataOffset + name.size, dataSize - name.size);
4122
4123 data[name.data] = value.data;
4124 } catch (e) {
4125 _logger2.default.e('AMF', e.toString());
4126 }
4127
4128 return data;
4129 }
4130 }, {
4131 key: 'parseObject',
4132 value: function parseObject(arrayBuffer, dataOffset, dataSize) {
4133 if (dataSize < 3) {
4134 throw new _exception.IllegalStateException('Data not enough when parse ScriptDataObject');
4135 }
4136 var name = AMF.parseString(arrayBuffer, dataOffset, dataSize);
4137 var value = AMF.parseValue(arrayBuffer, dataOffset + name.size, dataSize - name.size);
4138 var isObjectEnd = value.objectEnd;
4139
4140 return {
4141 data: {
4142 name: name.data,
4143 value: value.data
4144 },
4145 size: name.size + value.size,
4146 objectEnd: isObjectEnd
4147 };
4148 }
4149 }, {
4150 key: 'parseVariable',
4151 value: function parseVariable(arrayBuffer, dataOffset, dataSize) {
4152 return AMF.parseObject(arrayBuffer, dataOffset, dataSize);
4153 }
4154 }, {
4155 key: 'parseString',
4156 value: function parseString(arrayBuffer, dataOffset, dataSize) {
4157 if (dataSize < 2) {
4158 throw new _exception.IllegalStateException('Data not enough when parse String');
4159 }
4160 var v = new DataView(arrayBuffer, dataOffset, dataSize);
4161 var length = v.getUint16(0, !le);
4162
4163 var str = void 0;
4164 if (length > 0) {
4165 str = (0, _utf8Conv2.default)(new Uint8Array(arrayBuffer, dataOffset + 2, length));
4166 } else {
4167 str = '';
4168 }
4169
4170 return {
4171 data: str,
4172 size: 2 + length
4173 };
4174 }
4175 }, {
4176 key: 'parseLongString',
4177 value: function parseLongString(arrayBuffer, dataOffset, dataSize) {
4178 if (dataSize < 4) {
4179 throw new _exception.IllegalStateException('Data not enough when parse LongString');
4180 }
4181 var v = new DataView(arrayBuffer, dataOffset, dataSize);
4182 var length = v.getUint32(0, !le);
4183
4184 var str = void 0;
4185 if (length > 0) {
4186 str = (0, _utf8Conv2.default)(new Uint8Array(arrayBuffer, dataOffset + 4, length));
4187 } else {
4188 str = '';
4189 }
4190
4191 return {
4192 data: str,
4193 size: 4 + length
4194 };
4195 }
4196 }, {
4197 key: 'parseDate',
4198 value: function parseDate(arrayBuffer, dataOffset, dataSize) {
4199 if (dataSize < 10) {
4200 throw new _exception.IllegalStateException('Data size invalid when parse Date');
4201 }
4202 var v = new DataView(arrayBuffer, dataOffset, dataSize);
4203 var timestamp = v.getFloat64(0, !le);
4204 var localTimeOffset = v.getInt16(8, !le);
4205 timestamp += localTimeOffset * 60 * 1000; // get UTC time
4206
4207 return {
4208 data: new Date(timestamp),
4209 size: 8 + 2
4210 };
4211 }
4212 }, {
4213 key: 'parseValue',
4214 value: function parseValue(arrayBuffer, dataOffset, dataSize) {
4215 if (dataSize < 1) {
4216 throw new _exception.IllegalStateException('Data not enough when parse Value');
4217 }
4218
4219 var v = new DataView(arrayBuffer, dataOffset, dataSize);
4220
4221 var offset = 1;
4222 var type = v.getUint8(0);
4223 var value = void 0;
4224 var objectEnd = false;
4225
4226 try {
4227 switch (type) {
4228 case 0:
4229 // Number(Double) type
4230 value = v.getFloat64(1, !le);
4231 offset += 8;
4232 break;
4233 case 1:
4234 {
4235 // Boolean type
4236 var b = v.getUint8(1);
4237 value = b ? true : false;
4238 offset += 1;
4239 break;
4240 }
4241 case 2:
4242 {
4243 // String type
4244 var amfstr = AMF.parseString(arrayBuffer, dataOffset + 1, dataSize - 1);
4245 value = amfstr.data;
4246 offset += amfstr.size;
4247 break;
4248 }
4249 case 3:
4250 {
4251 // Object(s) type
4252 value = {};
4253 var terminal = 0; // workaround for malformed Objects which has missing ScriptDataObjectEnd
4254 if ((v.getUint32(dataSize - 4, !le) & 0x00FFFFFF) === 9) {
4255 terminal = 3;
4256 }
4257 while (offset < dataSize - 4) {
4258 // 4 === type(UI8) + ScriptDataObjectEnd(UI24)
4259 var amfobj = AMF.parseObject(arrayBuffer, dataOffset + offset, dataSize - offset - terminal);
4260 if (amfobj.objectEnd) break;
4261 value[amfobj.data.name] = amfobj.data.value;
4262 offset += amfobj.size;
4263 }
4264 if (offset <= dataSize - 3) {
4265 var marker = v.getUint32(offset - 1, !le) & 0x00FFFFFF;
4266 if (marker === 9) {
4267 offset += 3;
4268 }
4269 }
4270 break;
4271 }
4272 case 8:
4273 {
4274 // ECMA array type (Mixed array)
4275 value = {};
4276 offset += 4; // ECMAArrayLength(UI32)
4277 var _terminal = 0; // workaround for malformed MixedArrays which has missing ScriptDataObjectEnd
4278 if ((v.getUint32(dataSize - 4, !le) & 0x00FFFFFF) === 9) {
4279 _terminal = 3;
4280 }
4281 while (offset < dataSize - 8) {
4282 // 8 === type(UI8) + ECMAArrayLength(UI32) + ScriptDataVariableEnd(UI24)
4283 var amfvar = AMF.parseVariable(arrayBuffer, dataOffset + offset, dataSize - offset - _terminal);
4284 if (amfvar.objectEnd) break;
4285 value[amfvar.data.name] = amfvar.data.value;
4286 offset += amfvar.size;
4287 }
4288 if (offset <= dataSize - 3) {
4289 var _marker = v.getUint32(offset - 1, !le) & 0x00FFFFFF;
4290 if (_marker === 9) {
4291 offset += 3;
4292 }
4293 }
4294 break;
4295 }
4296 case 9:
4297 // ScriptDataObjectEnd
4298 value = undefined;
4299 offset = 1;
4300 objectEnd = true;
4301 break;
4302 case 10:
4303 {
4304 // Strict array type
4305 // ScriptDataValue[n]. NOTE: according to video_file_format_spec_v10_1.pdf
4306 value = [];
4307 var strictArrayLength = v.getUint32(1, !le);
4308 offset += 4;
4309 for (var i = 0; i < strictArrayLength; i++) {
4310 var val = AMF.parseValue(arrayBuffer, dataOffset + offset, dataSize - offset);
4311 value.push(val.data);
4312 offset += val.size;
4313 }
4314 break;
4315 }
4316 case 11:
4317 {
4318 // Date type
4319 var date = AMF.parseDate(arrayBuffer, dataOffset + 1, dataSize - 1);
4320 value = date.data;
4321 offset += date.size;
4322 break;
4323 }
4324 case 12:
4325 {
4326 // Long string type
4327 var amfLongStr = AMF.parseString(arrayBuffer, dataOffset + 1, dataSize - 1);
4328 value = amfLongStr.data;
4329 offset += amfLongStr.size;
4330 break;
4331 }
4332 default:
4333 // ignore and skip
4334 offset = dataSize;
4335 _logger2.default.w('AMF', 'Unsupported AMF value type ' + type);
4336 }
4337 } catch (e) {
4338 _logger2.default.e('AMF', e.toString());
4339 }
4340
4341 return {
4342 data: value,
4343 size: offset,
4344 objectEnd: objectEnd
4345 };
4346 }
4347 }]);
4348
4349 return AMF;
4350}();
4351
4352exports.default = AMF;
4353
4354},{"../utils/exception.js":40,"../utils/logger.js":41,"../utils/utf8-conv.js":44}],16:[function(_dereq_,module,exports){
4355'use strict';
4356
4357Object.defineProperty(exports, "__esModule", {
4358 value: true
4359});
4360/*
4361 * Copyright (C) 2016 Bilibili. All Rights Reserved.
4362 *
4363 * @author zheng qian <xqq@xqq.im>
4364 *
4365 * Licensed under the Apache License, Version 2.0 (the "License");
4366 * you may not use this file except in compliance with the License.
4367 * You may obtain a copy of the License at
4368 *
4369 * http://www.apache.org/licenses/LICENSE-2.0
4370 *
4371 * Unless required by applicable law or agreed to in writing, software
4372 * distributed under the License is distributed on an "AS IS" BASIS,
4373 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4374 * See the License for the specific language governing permissions and
4375 * limitations under the License.
4376 */
4377
4378var DemuxErrors = {
4379 OK: 'OK',
4380 FORMAT_ERROR: 'FormatError',
4381 FORMAT_UNSUPPORTED: 'FormatUnsupported',
4382 CODEC_UNSUPPORTED: 'CodecUnsupported'
4383};
4384
4385exports.default = DemuxErrors;
4386
4387},{}],17:[function(_dereq_,module,exports){
4388'use strict';
4389
4390Object.defineProperty(exports, "__esModule", {
4391 value: true
4392});
4393
4394var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
4395 * Copyright (C) 2016 Bilibili. All Rights Reserved.
4396 *
4397 * @author zheng qian <xqq@xqq.im>
4398 *
4399 * Licensed under the Apache License, Version 2.0 (the "License");
4400 * you may not use this file except in compliance with the License.
4401 * You may obtain a copy of the License at
4402 *
4403 * http://www.apache.org/licenses/LICENSE-2.0
4404 *
4405 * Unless required by applicable law or agreed to in writing, software
4406 * distributed under the License is distributed on an "AS IS" BASIS,
4407 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4408 * See the License for the specific language governing permissions and
4409 * limitations under the License.
4410 */
4411
4412var _exception = _dereq_('../utils/exception.js');
4413
4414function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4415
4416// Exponential-Golomb buffer decoder
4417var ExpGolomb = function () {
4418 function ExpGolomb(uint8array) {
4419 _classCallCheck(this, ExpGolomb);
4420
4421 this.TAG = 'ExpGolomb';
4422
4423 this._buffer = uint8array;
4424 this._buffer_index = 0;
4425 this._total_bytes = uint8array.byteLength;
4426 this._total_bits = uint8array.byteLength * 8;
4427 this._current_word = 0;
4428 this._current_word_bits_left = 0;
4429 }
4430
4431 _createClass(ExpGolomb, [{
4432 key: 'destroy',
4433 value: function destroy() {
4434 this._buffer = null;
4435 }
4436 }, {
4437 key: '_fillCurrentWord',
4438 value: function _fillCurrentWord() {
4439 var buffer_bytes_left = this._total_bytes - this._buffer_index;
4440 if (buffer_bytes_left <= 0) throw new _exception.IllegalStateException('ExpGolomb: _fillCurrentWord() but no bytes available');
4441
4442 var bytes_read = Math.min(4, buffer_bytes_left);
4443 var word = new Uint8Array(4);
4444 word.set(this._buffer.subarray(this._buffer_index, this._buffer_index + bytes_read));
4445 this._current_word = new DataView(word.buffer).getUint32(0, false);
4446
4447 this._buffer_index += bytes_read;
4448 this._current_word_bits_left = bytes_read * 8;
4449 }
4450 }, {
4451 key: 'readBits',
4452 value: function readBits(bits) {
4453 if (bits > 32) throw new _exception.InvalidArgumentException('ExpGolomb: readBits() bits exceeded max 32bits!');
4454
4455 if (bits <= this._current_word_bits_left) {
4456 var _result = this._current_word >>> 32 - bits;
4457 this._current_word <<= bits;
4458 this._current_word_bits_left -= bits;
4459 return _result;
4460 }
4461
4462 var result = this._current_word_bits_left ? this._current_word : 0;
4463 result = result >>> 32 - this._current_word_bits_left;
4464 var bits_need_left = bits - this._current_word_bits_left;
4465
4466 this._fillCurrentWord();
4467 var bits_read_next = Math.min(bits_need_left, this._current_word_bits_left);
4468
4469 var result2 = this._current_word >>> 32 - bits_read_next;
4470 this._current_word <<= bits_read_next;
4471 this._current_word_bits_left -= bits_read_next;
4472
4473 result = result << bits_read_next | result2;
4474 return result;
4475 }
4476 }, {
4477 key: 'readBool',
4478 value: function readBool() {
4479 return this.readBits(1) === 1;
4480 }
4481 }, {
4482 key: 'readByte',
4483 value: function readByte() {
4484 return this.readBits(8);
4485 }
4486 }, {
4487 key: '_skipLeadingZero',
4488 value: function _skipLeadingZero() {
4489 var zero_count = void 0;
4490 for (zero_count = 0; zero_count < this._current_word_bits_left; zero_count++) {
4491 if (0 !== (this._current_word & 0x80000000 >>> zero_count)) {
4492 this._current_word <<= zero_count;
4493 this._current_word_bits_left -= zero_count;
4494 return zero_count;
4495 }
4496 }
4497 this._fillCurrentWord();
4498 return zero_count + this._skipLeadingZero();
4499 }
4500 }, {
4501 key: 'readUEG',
4502 value: function readUEG() {
4503 // unsigned exponential golomb
4504 var leading_zeros = this._skipLeadingZero();
4505 return this.readBits(leading_zeros + 1) - 1;
4506 }
4507 }, {
4508 key: 'readSEG',
4509 value: function readSEG() {
4510 // signed exponential golomb
4511 var value = this.readUEG();
4512 if (value & 0x01) {
4513 return value + 1 >>> 1;
4514 } else {
4515 return -1 * (value >>> 1);
4516 }
4517 }
4518 }]);
4519
4520 return ExpGolomb;
4521}();
4522
4523exports.default = ExpGolomb;
4524
4525},{"../utils/exception.js":40}],18:[function(_dereq_,module,exports){
4526'use strict';
4527
4528Object.defineProperty(exports, "__esModule", {
4529 value: true
4530});
4531
4532var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
4533
4534var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
4535 * Copyright (C) 2016 Bilibili. All Rights Reserved.
4536 *
4537 * @author zheng qian <xqq@xqq.im>
4538 *
4539 * Licensed under the Apache License, Version 2.0 (the "License");
4540 * you may not use this file except in compliance with the License.
4541 * You may obtain a copy of the License at
4542 *
4543 * http://www.apache.org/licenses/LICENSE-2.0
4544 *
4545 * Unless required by applicable law or agreed to in writing, software
4546 * distributed under the License is distributed on an "AS IS" BASIS,
4547 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4548 * See the License for the specific language governing permissions and
4549 * limitations under the License.
4550 */
4551
4552var _logger = _dereq_('../utils/logger.js');
4553
4554var _logger2 = _interopRequireDefault(_logger);
4555
4556var _amfParser = _dereq_('./amf-parser.js');
4557
4558var _amfParser2 = _interopRequireDefault(_amfParser);
4559
4560var _spsParser = _dereq_('./sps-parser.js');
4561
4562var _spsParser2 = _interopRequireDefault(_spsParser);
4563
4564var _demuxErrors = _dereq_('./demux-errors.js');
4565
4566var _demuxErrors2 = _interopRequireDefault(_demuxErrors);
4567
4568var _mediaInfo = _dereq_('../core/media-info.js');
4569
4570var _mediaInfo2 = _interopRequireDefault(_mediaInfo);
4571
4572var _exception = _dereq_('../utils/exception.js');
4573
4574function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
4575
4576function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4577
4578function Swap16(src) {
4579 return src >>> 8 & 0xFF | (src & 0xFF) << 8;
4580}
4581
4582function Swap32(src) {
4583 return (src & 0xFF000000) >>> 24 | (src & 0x00FF0000) >>> 8 | (src & 0x0000FF00) << 8 | (src & 0x000000FF) << 24;
4584}
4585
4586function ReadBig32(array, index) {
4587 return array[index] << 24 | array[index + 1] << 16 | array[index + 2] << 8 | array[index + 3];
4588}
4589
4590var FLVDemuxer = function () {
4591 function FLVDemuxer(probeData, config) {
4592 _classCallCheck(this, FLVDemuxer);
4593
4594 this.TAG = 'FLVDemuxer';
4595
4596 this._config = config;
4597
4598 this._onError = null;
4599 this._onMediaInfo = null;
4600 this._onMetaDataArrived = null;
4601 this._onScriptDataArrived = null;
4602 this._onTrackMetadata = null;
4603 this._onDataAvailable = null;
4604
4605 this._dataOffset = probeData.dataOffset;
4606 this._firstParse = true;
4607 this._dispatch = false;
4608
4609 this._hasAudio = probeData.hasAudioTrack;
4610 this._hasVideo = probeData.hasVideoTrack;
4611
4612 this._hasAudioFlagOverrided = false;
4613 this._hasVideoFlagOverrided = false;
4614
4615 this._audioInitialMetadataDispatched = false;
4616 this._videoInitialMetadataDispatched = false;
4617
4618 this._mediaInfo = new _mediaInfo2.default();
4619 this._mediaInfo.hasAudio = this._hasAudio;
4620 this._mediaInfo.hasVideo = this._hasVideo;
4621 this._metadata = null;
4622 this._audioMetadata = null;
4623 this._videoMetadata = null;
4624
4625 this._naluLengthSize = 4;
4626 this._timestampBase = 0; // int32, in milliseconds
4627 this._timescale = 1000;
4628 this._duration = 0; // int32, in milliseconds
4629 this._durationOverrided = false;
4630 this._referenceFrameRate = {
4631 fixed: true,
4632 fps: 23.976,
4633 fps_num: 23976,
4634 fps_den: 1000
4635 };
4636
4637 this._flvSoundRateTable = [5500, 11025, 22050, 44100, 48000];
4638
4639 this._mpegSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
4640
4641 this._mpegAudioV10SampleRateTable = [44100, 48000, 32000, 0];
4642 this._mpegAudioV20SampleRateTable = [22050, 24000, 16000, 0];
4643 this._mpegAudioV25SampleRateTable = [11025, 12000, 8000, 0];
4644
4645 this._mpegAudioL1BitRateTable = [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1];
4646 this._mpegAudioL2BitRateTable = [0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1];
4647 this._mpegAudioL3BitRateTable = [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1];
4648
4649 this._videoTrack = { type: 'video', id: 1, sequenceNumber: 0, samples: [], length: 0 };
4650 this._audioTrack = { type: 'audio', id: 2, sequenceNumber: 0, samples: [], length: 0 };
4651
4652 this._littleEndian = function () {
4653 var buf = new ArrayBuffer(2);
4654 new DataView(buf).setInt16(0, 256, true); // little-endian write
4655 return new Int16Array(buf)[0] === 256; // platform-spec read, if equal then LE
4656 }();
4657 }
4658
4659 _createClass(FLVDemuxer, [{
4660 key: 'destroy',
4661 value: function destroy() {
4662 this._mediaInfo = null;
4663 this._metadata = null;
4664 this._audioMetadata = null;
4665 this._videoMetadata = null;
4666 this._videoTrack = null;
4667 this._audioTrack = null;
4668
4669 this._onError = null;
4670 this._onMediaInfo = null;
4671 this._onMetaDataArrived = null;
4672 this._onScriptDataArrived = null;
4673 this._onTrackMetadata = null;
4674 this._onDataAvailable = null;
4675 }
4676 }, {
4677 key: 'bindDataSource',
4678 value: function bindDataSource(loader) {
4679 loader.onDataArrival = this.parseChunks.bind(this);
4680 return this;
4681 }
4682
4683 // prototype: function(type: string, metadata: any): void
4684
4685 }, {
4686 key: 'resetMediaInfo',
4687 value: function resetMediaInfo() {
4688 this._mediaInfo = new _mediaInfo2.default();
4689 }
4690 }, {
4691 key: '_isInitialMetadataDispatched',
4692 value: function _isInitialMetadataDispatched() {
4693 if (this._hasAudio && this._hasVideo) {
4694 // both audio & video
4695 return this._audioInitialMetadataDispatched && this._videoInitialMetadataDispatched;
4696 }
4697 if (this._hasAudio && !this._hasVideo) {
4698 // audio only
4699 return this._audioInitialMetadataDispatched;
4700 }
4701 if (!this._hasAudio && this._hasVideo) {
4702 // video only
4703 return this._videoInitialMetadataDispatched;
4704 }
4705 return false;
4706 }
4707
4708 // function parseChunks(chunk: ArrayBuffer, byteStart: number): number;
4709
4710 }, {
4711 key: 'parseChunks',
4712 value: function parseChunks(chunk, byteStart) {
4713 if (!this._onError || !this._onMediaInfo || !this._onTrackMetadata || !this._onDataAvailable) {
4714 throw new _exception.IllegalStateException('Flv: onError & onMediaInfo & onTrackMetadata & onDataAvailable callback must be specified');
4715 }
4716
4717 var offset = 0;
4718 var le = this._littleEndian;
4719
4720 if (byteStart === 0) {
4721 // buffer with FLV header
4722 if (chunk.byteLength > 13) {
4723 var probeData = FLVDemuxer.probe(chunk);
4724 offset = probeData.dataOffset;
4725 } else {
4726 return 0;
4727 }
4728 }
4729
4730 if (this._firstParse) {
4731 // handle PreviousTagSize0 before Tag1
4732 this._firstParse = false;
4733 if (byteStart + offset !== this._dataOffset) {
4734 _logger2.default.w(this.TAG, 'First time parsing but chunk byteStart invalid!');
4735 }
4736
4737 var v = new DataView(chunk, offset);
4738 var prevTagSize0 = v.getUint32(0, !le);
4739 if (prevTagSize0 !== 0) {
4740 _logger2.default.w(this.TAG, 'PrevTagSize0 !== 0 !!!');
4741 }
4742 offset += 4;
4743 }
4744
4745 while (offset < chunk.byteLength) {
4746 this._dispatch = true;
4747
4748 var _v = new DataView(chunk, offset);
4749
4750 if (offset + 11 + 4 > chunk.byteLength) {
4751 // data not enough for parsing an flv tag
4752 break;
4753 }
4754
4755 var tagType = _v.getUint8(0);
4756 var dataSize = _v.getUint32(0, !le) & 0x00FFFFFF;
4757
4758 if (offset + 11 + dataSize + 4 > chunk.byteLength) {
4759 // data not enough for parsing actual data body
4760 break;
4761 }
4762
4763 if (tagType !== 8 && tagType !== 9 && tagType !== 18) {
4764 _logger2.default.w(this.TAG, 'Unsupported tag type ' + tagType + ', skipped');
4765 // consume the whole tag (skip it)
4766 offset += 11 + dataSize + 4;
4767 continue;
4768 }
4769
4770 var ts2 = _v.getUint8(4);
4771 var ts1 = _v.getUint8(5);
4772 var ts0 = _v.getUint8(6);
4773 var ts3 = _v.getUint8(7);
4774
4775 var timestamp = ts0 | ts1 << 8 | ts2 << 16 | ts3 << 24;
4776
4777 var streamId = _v.getUint32(7, !le) & 0x00FFFFFF;
4778 if (streamId !== 0) {
4779 _logger2.default.w(this.TAG, 'Meet tag which has StreamID != 0!');
4780 }
4781
4782 var dataOffset = offset + 11;
4783
4784 switch (tagType) {
4785 case 8:
4786 // Audio
4787 this._parseAudioData(chunk, dataOffset, dataSize, timestamp);
4788 break;
4789 case 9:
4790 // Video
4791 this._parseVideoData(chunk, dataOffset, dataSize, timestamp, byteStart + offset);
4792 break;
4793 case 18:
4794 // ScriptDataObject
4795 this._parseScriptData(chunk, dataOffset, dataSize);
4796 break;
4797 }
4798
4799 var prevTagSize = _v.getUint32(11 + dataSize, !le);
4800 if (prevTagSize !== 11 + dataSize) {
4801 _logger2.default.w(this.TAG, 'Invalid PrevTagSize ' + prevTagSize);
4802 }
4803
4804 offset += 11 + dataSize + 4; // tagBody + dataSize + prevTagSize
4805 }
4806
4807 // dispatch parsed frames to consumer (typically, the remuxer)
4808 if (this._isInitialMetadataDispatched()) {
4809 if (this._dispatch && (this._audioTrack.length || this._videoTrack.length)) {
4810 this._onDataAvailable(this._audioTrack, this._videoTrack);
4811 }
4812 }
4813
4814 return offset; // consumed bytes, just equals latest offset index
4815 }
4816 }, {
4817 key: '_parseScriptData',
4818 value: function _parseScriptData(arrayBuffer, dataOffset, dataSize) {
4819 var scriptData = _amfParser2.default.parseScriptData(arrayBuffer, dataOffset, dataSize);
4820
4821 if (scriptData.hasOwnProperty('onMetaData')) {
4822 if (scriptData.onMetaData == null || _typeof(scriptData.onMetaData) !== 'object') {
4823 _logger2.default.w(this.TAG, 'Invalid onMetaData structure!');
4824 return;
4825 }
4826 if (this._metadata) {
4827 _logger2.default.w(this.TAG, 'Found another onMetaData tag!');
4828 }
4829 this._metadata = scriptData;
4830 var onMetaData = this._metadata.onMetaData;
4831
4832 if (this._onMetaDataArrived) {
4833 this._onMetaDataArrived(Object.assign({}, onMetaData));
4834 }
4835
4836 if (typeof onMetaData.hasAudio === 'boolean') {
4837 // hasAudio
4838 if (this._hasAudioFlagOverrided === false) {
4839 this._hasAudio = onMetaData.hasAudio;
4840 this._mediaInfo.hasAudio = this._hasAudio;
4841 }
4842 }
4843 if (typeof onMetaData.hasVideo === 'boolean') {
4844 // hasVideo
4845 if (this._hasVideoFlagOverrided === false) {
4846 this._hasVideo = onMetaData.hasVideo;
4847 this._mediaInfo.hasVideo = this._hasVideo;
4848 }
4849 }
4850 if (typeof onMetaData.audiodatarate === 'number') {
4851 // audiodatarate
4852 this._mediaInfo.audioDataRate = onMetaData.audiodatarate;
4853 }
4854 if (typeof onMetaData.videodatarate === 'number') {
4855 // videodatarate
4856 this._mediaInfo.videoDataRate = onMetaData.videodatarate;
4857 }
4858 if (typeof onMetaData.width === 'number') {
4859 // width
4860 this._mediaInfo.width = onMetaData.width;
4861 }
4862 if (typeof onMetaData.height === 'number') {
4863 // height
4864 this._mediaInfo.height = onMetaData.height;
4865 }
4866 if (typeof onMetaData.duration === 'number') {
4867 // duration
4868 if (!this._durationOverrided) {
4869 var duration = Math.floor(onMetaData.duration * this._timescale);
4870 this._duration = duration;
4871 this._mediaInfo.duration = duration;
4872 }
4873 } else {
4874 this._mediaInfo.duration = 0;
4875 }
4876 if (typeof onMetaData.framerate === 'number') {
4877 // framerate
4878 var fps_num = Math.floor(onMetaData.framerate * 1000);
4879 if (fps_num > 0) {
4880 var fps = fps_num / 1000;
4881 this._referenceFrameRate.fixed = true;
4882 this._referenceFrameRate.fps = fps;
4883 this._referenceFrameRate.fps_num = fps_num;
4884 this._referenceFrameRate.fps_den = 1000;
4885 this._mediaInfo.fps = fps;
4886 }
4887 }
4888 if (_typeof(onMetaData.keyframes) === 'object') {
4889 // keyframes
4890 this._mediaInfo.hasKeyframesIndex = true;
4891 var keyframes = onMetaData.keyframes;
4892 this._mediaInfo.keyframesIndex = this._parseKeyframesIndex(keyframes);
4893 onMetaData.keyframes = null; // keyframes has been extracted, remove it
4894 } else {
4895 this._mediaInfo.hasKeyframesIndex = false;
4896 }
4897 this._dispatch = false;
4898 this._mediaInfo.metadata = onMetaData;
4899 _logger2.default.v(this.TAG, 'Parsed onMetaData');
4900 if (this._mediaInfo.isComplete()) {
4901 this._onMediaInfo(this._mediaInfo);
4902 }
4903 }
4904
4905 if (Object.keys(scriptData).length > 0) {
4906 if (this._onScriptDataArrived) {
4907 this._onScriptDataArrived(Object.assign({}, scriptData));
4908 }
4909 }
4910 }
4911 }, {
4912 key: '_parseKeyframesIndex',
4913 value: function _parseKeyframesIndex(keyframes) {
4914 var times = [];
4915 var filepositions = [];
4916
4917 // ignore first keyframe which is actually AVC Sequence Header (AVCDecoderConfigurationRecord)
4918 for (var i = 1; i < keyframes.times.length; i++) {
4919 var time = this._timestampBase + Math.floor(keyframes.times[i] * 1000);
4920 times.push(time);
4921 filepositions.push(keyframes.filepositions[i]);
4922 }
4923
4924 return {
4925 times: times,
4926 filepositions: filepositions
4927 };
4928 }
4929 }, {
4930 key: '_parseAudioData',
4931 value: function _parseAudioData(arrayBuffer, dataOffset, dataSize, tagTimestamp) {
4932 if (dataSize <= 1) {
4933 _logger2.default.w(this.TAG, 'Flv: Invalid audio packet, missing SoundData payload!');
4934 return;
4935 }
4936
4937 if (this._hasAudioFlagOverrided === true && this._hasAudio === false) {
4938 // If hasAudio: false indicated explicitly in MediaDataSource,
4939 // Ignore all the audio packets
4940 return;
4941 }
4942
4943 var le = this._littleEndian;
4944 var v = new DataView(arrayBuffer, dataOffset, dataSize);
4945
4946 var soundSpec = v.getUint8(0);
4947
4948 var soundFormat = soundSpec >>> 4;
4949 if (soundFormat !== 2 && soundFormat !== 10) {
4950 // MP3 or AAC
4951 this._onError(_demuxErrors2.default.CODEC_UNSUPPORTED, 'Flv: Unsupported audio codec idx: ' + soundFormat);
4952 return;
4953 }
4954
4955 var soundRate = 0;
4956 var soundRateIndex = (soundSpec & 12) >>> 2;
4957 if (soundRateIndex >= 0 && soundRateIndex <= 4) {
4958 soundRate = this._flvSoundRateTable[soundRateIndex];
4959 } else {
4960 this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid audio sample rate idx: ' + soundRateIndex);
4961 return;
4962 }
4963
4964 var soundSize = (soundSpec & 2) >>> 1; // unused
4965 var soundType = soundSpec & 1;
4966
4967 var meta = this._audioMetadata;
4968 var track = this._audioTrack;
4969
4970 if (!meta) {
4971 if (this._hasAudio === false && this._hasAudioFlagOverrided === false) {
4972 this._hasAudio = true;
4973 this._mediaInfo.hasAudio = true;
4974 }
4975
4976 // initial metadata
4977 meta = this._audioMetadata = {};
4978 meta.type = 'audio';
4979 meta.id = track.id;
4980 meta.timescale = this._timescale;
4981 meta.duration = this._duration;
4982 meta.audioSampleRate = soundRate;
4983 meta.channelCount = soundType === 0 ? 1 : 2;
4984 }
4985
4986 if (soundFormat === 10) {
4987 // AAC
4988 var aacData = this._parseAACAudioData(arrayBuffer, dataOffset + 1, dataSize - 1);
4989 if (aacData == undefined) {
4990 return;
4991 }
4992
4993 if (aacData.packetType === 0) {
4994 // AAC sequence header (AudioSpecificConfig)
4995 if (meta.config) {
4996 _logger2.default.w(this.TAG, 'Found another AudioSpecificConfig!');
4997 }
4998 var misc = aacData.data;
4999 meta.audioSampleRate = misc.samplingRate;
5000 meta.channelCount = misc.channelCount;
5001 meta.codec = misc.codec;
5002 meta.originalCodec = misc.originalCodec;
5003 meta.config = misc.config;
5004 // The decode result of an aac sample is 1024 PCM samples
5005 meta.refSampleDuration = 1024 / meta.audioSampleRate * meta.timescale;
5006 _logger2.default.v(this.TAG, 'Parsed AudioSpecificConfig');
5007
5008 if (this._isInitialMetadataDispatched()) {
5009 // Non-initial metadata, force dispatch (or flush) parsed frames to remuxer
5010 if (this._dispatch && (this._audioTrack.length || this._videoTrack.length)) {
5011 this._onDataAvailable(this._audioTrack, this._videoTrack);
5012 }
5013 } else {
5014 this._audioInitialMetadataDispatched = true;
5015 }
5016 // then notify new metadata
5017 this._dispatch = false;
5018 this._onTrackMetadata('audio', meta);
5019
5020 var mi = this._mediaInfo;
5021 mi.audioCodec = meta.originalCodec;
5022 mi.audioSampleRate = meta.audioSampleRate;
5023 mi.audioChannelCount = meta.channelCount;
5024 if (mi.hasVideo) {
5025 if (mi.videoCodec != null) {
5026 mi.mimeType = 'video/x-flv; codecs="' + mi.videoCodec + ',' + mi.audioCodec + '"';
5027 }
5028 } else {
5029 mi.mimeType = 'video/x-flv; codecs="' + mi.audioCodec + '"';
5030 }
5031 if (mi.isComplete()) {
5032 this._onMediaInfo(mi);
5033 }
5034 } else if (aacData.packetType === 1) {
5035 // AAC raw frame data
5036 var dts = this._timestampBase + tagTimestamp;
5037 var aacSample = { unit: aacData.data, length: aacData.data.byteLength, dts: dts, pts: dts };
5038 track.samples.push(aacSample);
5039 track.length += aacData.data.length;
5040 } else {
5041 _logger2.default.e(this.TAG, 'Flv: Unsupported AAC data type ' + aacData.packetType);
5042 }
5043 } else if (soundFormat === 2) {
5044 // MP3
5045 if (!meta.codec) {
5046 // We need metadata for mp3 audio track, extract info from frame header
5047 var _misc = this._parseMP3AudioData(arrayBuffer, dataOffset + 1, dataSize - 1, true);
5048 if (_misc == undefined) {
5049 return;
5050 }
5051 meta.audioSampleRate = _misc.samplingRate;
5052 meta.channelCount = _misc.channelCount;
5053 meta.codec = _misc.codec;
5054 meta.originalCodec = _misc.originalCodec;
5055 // The decode result of an mp3 sample is 1152 PCM samples
5056 meta.refSampleDuration = 1152 / meta.audioSampleRate * meta.timescale;
5057 _logger2.default.v(this.TAG, 'Parsed MPEG Audio Frame Header');
5058
5059 this._audioInitialMetadataDispatched = true;
5060 this._onTrackMetadata('audio', meta);
5061
5062 var _mi = this._mediaInfo;
5063 _mi.audioCodec = meta.codec;
5064 _mi.audioSampleRate = meta.audioSampleRate;
5065 _mi.audioChannelCount = meta.channelCount;
5066 _mi.audioDataRate = _misc.bitRate;
5067 if (_mi.hasVideo) {
5068 if (_mi.videoCodec != null) {
5069 _mi.mimeType = 'video/x-flv; codecs="' + _mi.videoCodec + ',' + _mi.audioCodec + '"';
5070 }
5071 } else {
5072 _mi.mimeType = 'video/x-flv; codecs="' + _mi.audioCodec + '"';
5073 }
5074 if (_mi.isComplete()) {
5075 this._onMediaInfo(_mi);
5076 }
5077 }
5078
5079 // This packet is always a valid audio packet, extract it
5080 var data = this._parseMP3AudioData(arrayBuffer, dataOffset + 1, dataSize - 1, false);
5081 if (data == undefined) {
5082 return;
5083 }
5084 var _dts = this._timestampBase + tagTimestamp;
5085 var mp3Sample = { unit: data, length: data.byteLength, dts: _dts, pts: _dts };
5086 track.samples.push(mp3Sample);
5087 track.length += data.length;
5088 }
5089 }
5090 }, {
5091 key: '_parseAACAudioData',
5092 value: function _parseAACAudioData(arrayBuffer, dataOffset, dataSize) {
5093 if (dataSize <= 1) {
5094 _logger2.default.w(this.TAG, 'Flv: Invalid AAC packet, missing AACPacketType or/and Data!');
5095 return;
5096 }
5097
5098 var result = {};
5099 var array = new Uint8Array(arrayBuffer, dataOffset, dataSize);
5100
5101 result.packetType = array[0];
5102
5103 if (array[0] === 0) {
5104 result.data = this._parseAACAudioSpecificConfig(arrayBuffer, dataOffset + 1, dataSize - 1);
5105 } else {
5106 result.data = array.subarray(1);
5107 }
5108
5109 return result;
5110 }
5111 }, {
5112 key: '_parseAACAudioSpecificConfig',
5113 value: function _parseAACAudioSpecificConfig(arrayBuffer, dataOffset, dataSize) {
5114 var array = new Uint8Array(arrayBuffer, dataOffset, dataSize);
5115 var config = null;
5116
5117 /* Audio Object Type:
5118 0: Null
5119 1: AAC Main
5120 2: AAC LC
5121 3: AAC SSR (Scalable Sample Rate)
5122 4: AAC LTP (Long Term Prediction)
5123 5: HE-AAC / SBR (Spectral Band Replication)
5124 6: AAC Scalable
5125 */
5126
5127 var audioObjectType = 0;
5128 var originalAudioObjectType = 0;
5129 var audioExtensionObjectType = null;
5130 var samplingIndex = 0;
5131 var extensionSamplingIndex = null;
5132
5133 // 5 bits
5134 audioObjectType = originalAudioObjectType = array[0] >>> 3;
5135 // 4 bits
5136 samplingIndex = (array[0] & 0x07) << 1 | array[1] >>> 7;
5137 if (samplingIndex < 0 || samplingIndex >= this._mpegSamplingRates.length) {
5138 this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: AAC invalid sampling frequency index!');
5139 return;
5140 }
5141
5142 var samplingFrequence = this._mpegSamplingRates[samplingIndex];
5143
5144 // 4 bits
5145 var channelConfig = (array[1] & 0x78) >>> 3;
5146 if (channelConfig < 0 || channelConfig >= 8) {
5147 this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: AAC invalid channel configuration');
5148 return;
5149 }
5150
5151 if (audioObjectType === 5) {
5152 // HE-AAC?
5153 // 4 bits
5154 extensionSamplingIndex = (array[1] & 0x07) << 1 | array[2] >>> 7;
5155 // 5 bits
5156 audioExtensionObjectType = (array[2] & 0x7C) >>> 2;
5157 }
5158
5159 // workarounds for various browsers
5160 var userAgent = self.navigator.userAgent.toLowerCase();
5161
5162 if (userAgent.indexOf('firefox') !== -1) {
5163 // firefox: use SBR (HE-AAC) if freq less than 24kHz
5164 if (samplingIndex >= 6) {
5165 audioObjectType = 5;
5166 config = new Array(4);
5167 extensionSamplingIndex = samplingIndex - 3;
5168 } else {
5169 // use LC-AAC
5170 audioObjectType = 2;
5171 config = new Array(2);
5172 extensionSamplingIndex = samplingIndex;
5173 }
5174 } else if (userAgent.indexOf('android') !== -1) {
5175 // android: always use LC-AAC
5176 audioObjectType = 2;
5177 config = new Array(2);
5178 extensionSamplingIndex = samplingIndex;
5179 } else {
5180 // for other browsers, e.g. chrome...
5181 // Always use HE-AAC to make it easier to switch aac codec profile
5182 audioObjectType = 5;
5183 extensionSamplingIndex = samplingIndex;
5184 config = new Array(4);
5185
5186 if (samplingIndex >= 6) {
5187 extensionSamplingIndex = samplingIndex - 3;
5188 } else if (channelConfig === 1) {
5189 // Mono channel
5190 audioObjectType = 2;
5191 config = new Array(2);
5192 extensionSamplingIndex = samplingIndex;
5193 }
5194 }
5195
5196 config[0] = audioObjectType << 3;
5197 config[0] |= (samplingIndex & 0x0F) >>> 1;
5198 config[1] = (samplingIndex & 0x0F) << 7;
5199 config[1] |= (channelConfig & 0x0F) << 3;
5200 if (audioObjectType === 5) {
5201 config[1] |= (extensionSamplingIndex & 0x0F) >>> 1;
5202 config[2] = (extensionSamplingIndex & 0x01) << 7;
5203 // extended audio object type: force to 2 (LC-AAC)
5204 config[2] |= 2 << 2;
5205 config[3] = 0;
5206 }
5207
5208 return {
5209 config: config,
5210 samplingRate: samplingFrequence,
5211 channelCount: channelConfig,
5212 codec: 'mp4a.40.' + audioObjectType,
5213 originalCodec: 'mp4a.40.' + originalAudioObjectType
5214 };
5215 }
5216 }, {
5217 key: '_parseMP3AudioData',
5218 value: function _parseMP3AudioData(arrayBuffer, dataOffset, dataSize, requestHeader) {
5219 if (dataSize < 4) {
5220 _logger2.default.w(this.TAG, 'Flv: Invalid MP3 packet, header missing!');
5221 return;
5222 }
5223
5224 var le = this._littleEndian;
5225 var array = new Uint8Array(arrayBuffer, dataOffset, dataSize);
5226 var result = null;
5227
5228 if (requestHeader) {
5229 if (array[0] !== 0xFF) {
5230 return;
5231 }
5232 var ver = array[1] >>> 3 & 0x03;
5233 var layer = (array[1] & 0x06) >> 1;
5234
5235 var bitrate_index = (array[2] & 0xF0) >>> 4;
5236 var sampling_freq_index = (array[2] & 0x0C) >>> 2;
5237
5238 var channel_mode = array[3] >>> 6 & 0x03;
5239 var channel_count = channel_mode !== 3 ? 2 : 1;
5240
5241 var sample_rate = 0;
5242 var bit_rate = 0;
5243 var object_type = 34; // Layer-3, listed in MPEG-4 Audio Object Types
5244
5245 var codec = 'mp3';
5246
5247 switch (ver) {
5248 case 0:
5249 // MPEG 2.5
5250 sample_rate = this._mpegAudioV25SampleRateTable[sampling_freq_index];
5251 break;
5252 case 2:
5253 // MPEG 2
5254 sample_rate = this._mpegAudioV20SampleRateTable[sampling_freq_index];
5255 break;
5256 case 3:
5257 // MPEG 1
5258 sample_rate = this._mpegAudioV10SampleRateTable[sampling_freq_index];
5259 break;
5260 }
5261
5262 switch (layer) {
5263 case 1:
5264 // Layer 3
5265 object_type = 34;
5266 if (bitrate_index < this._mpegAudioL3BitRateTable.length) {
5267 bit_rate = this._mpegAudioL3BitRateTable[bitrate_index];
5268 }
5269 break;
5270 case 2:
5271 // Layer 2
5272 object_type = 33;
5273 if (bitrate_index < this._mpegAudioL2BitRateTable.length) {
5274 bit_rate = this._mpegAudioL2BitRateTable[bitrate_index];
5275 }
5276 break;
5277 case 3:
5278 // Layer 1
5279 object_type = 32;
5280 if (bitrate_index < this._mpegAudioL1BitRateTable.length) {
5281 bit_rate = this._mpegAudioL1BitRateTable[bitrate_index];
5282 }
5283 break;
5284 }
5285
5286 result = {
5287 bitRate: bit_rate,
5288 samplingRate: sample_rate,
5289 channelCount: channel_count,
5290 codec: codec,
5291 originalCodec: codec
5292 };
5293 } else {
5294 result = array;
5295 }
5296
5297 return result;
5298 }
5299 }, {
5300 key: '_parseVideoData',
5301 value: function _parseVideoData(arrayBuffer, dataOffset, dataSize, tagTimestamp, tagPosition) {
5302 if (dataSize <= 1) {
5303 _logger2.default.w(this.TAG, 'Flv: Invalid video packet, missing VideoData payload!');
5304 return;
5305 }
5306
5307 if (this._hasVideoFlagOverrided === true && this._hasVideo === false) {
5308 // If hasVideo: false indicated explicitly in MediaDataSource,
5309 // Ignore all the video packets
5310 return;
5311 }
5312
5313 var spec = new Uint8Array(arrayBuffer, dataOffset, dataSize)[0];
5314
5315 var frameType = (spec & 240) >>> 4;
5316 var codecId = spec & 15;
5317
5318 if (codecId !== 7) {
5319 this._onError(_demuxErrors2.default.CODEC_UNSUPPORTED, 'Flv: Unsupported codec in video frame: ' + codecId);
5320 return;
5321 }
5322
5323 this._parseAVCVideoPacket(arrayBuffer, dataOffset + 1, dataSize - 1, tagTimestamp, tagPosition, frameType);
5324 }
5325 }, {
5326 key: '_parseAVCVideoPacket',
5327 value: function _parseAVCVideoPacket(arrayBuffer, dataOffset, dataSize, tagTimestamp, tagPosition, frameType) {
5328 if (dataSize < 4) {
5329 _logger2.default.w(this.TAG, 'Flv: Invalid AVC packet, missing AVCPacketType or/and CompositionTime');
5330 return;
5331 }
5332
5333 var le = this._littleEndian;
5334 var v = new DataView(arrayBuffer, dataOffset, dataSize);
5335
5336 var packetType = v.getUint8(0);
5337 var cts_unsigned = v.getUint32(0, !le) & 0x00FFFFFF;
5338 var cts = cts_unsigned << 8 >> 8; // convert to 24-bit signed int
5339
5340 if (packetType === 0) {
5341 // AVCDecoderConfigurationRecord
5342 this._parseAVCDecoderConfigurationRecord(arrayBuffer, dataOffset + 4, dataSize - 4);
5343 } else if (packetType === 1) {
5344 // One or more Nalus
5345 this._parseAVCVideoData(arrayBuffer, dataOffset + 4, dataSize - 4, tagTimestamp, tagPosition, frameType, cts);
5346 } else if (packetType === 2) {
5347 // empty, AVC end of sequence
5348 } else {
5349 this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid video packet type ' + packetType);
5350 return;
5351 }
5352 }
5353 }, {
5354 key: '_parseAVCDecoderConfigurationRecord',
5355 value: function _parseAVCDecoderConfigurationRecord(arrayBuffer, dataOffset, dataSize) {
5356 if (dataSize < 7) {
5357 _logger2.default.w(this.TAG, 'Flv: Invalid AVCDecoderConfigurationRecord, lack of data!');
5358 return;
5359 }
5360
5361 var meta = this._videoMetadata;
5362 var track = this._videoTrack;
5363 var le = this._littleEndian;
5364 var v = new DataView(arrayBuffer, dataOffset, dataSize);
5365
5366 if (!meta) {
5367 if (this._hasVideo === false && this._hasVideoFlagOverrided === false) {
5368 this._hasVideo = true;
5369 this._mediaInfo.hasVideo = true;
5370 }
5371
5372 meta = this._videoMetadata = {};
5373 meta.type = 'video';
5374 meta.id = track.id;
5375 meta.timescale = this._timescale;
5376 meta.duration = this._duration;
5377 } else {
5378 if (typeof meta.avcc !== 'undefined') {
5379 _logger2.default.w(this.TAG, 'Found another AVCDecoderConfigurationRecord!');
5380 }
5381 }
5382
5383 var version = v.getUint8(0); // configurationVersion
5384 var avcProfile = v.getUint8(1); // avcProfileIndication
5385 var profileCompatibility = v.getUint8(2); // profile_compatibility
5386 var avcLevel = v.getUint8(3); // AVCLevelIndication
5387
5388 if (version !== 1 || avcProfile === 0) {
5389 this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid AVCDecoderConfigurationRecord');
5390 return;
5391 }
5392
5393 this._naluLengthSize = (v.getUint8(4) & 3) + 1; // lengthSizeMinusOne
5394 if (this._naluLengthSize !== 3 && this._naluLengthSize !== 4) {
5395 // holy shit!!!
5396 this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Strange NaluLengthSizeMinusOne: ' + (this._naluLengthSize - 1));
5397 return;
5398 }
5399
5400 var spsCount = v.getUint8(5) & 31; // numOfSequenceParameterSets
5401 if (spsCount === 0) {
5402 this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid AVCDecoderConfigurationRecord: No SPS');
5403 return;
5404 } else if (spsCount > 1) {
5405 _logger2.default.w(this.TAG, 'Flv: Strange AVCDecoderConfigurationRecord: SPS Count = ' + spsCount);
5406 }
5407
5408 var offset = 6;
5409
5410 for (var i = 0; i < spsCount; i++) {
5411 var len = v.getUint16(offset, !le); // sequenceParameterSetLength
5412 offset += 2;
5413
5414 if (len === 0) {
5415 continue;
5416 }
5417
5418 // Notice: Nalu without startcode header (00 00 00 01)
5419 var sps = new Uint8Array(arrayBuffer, dataOffset + offset, len);
5420 offset += len;
5421
5422 var config = _spsParser2.default.parseSPS(sps);
5423 if (i !== 0) {
5424 // ignore other sps's config
5425 continue;
5426 }
5427
5428 meta.codecWidth = config.codec_size.width;
5429 meta.codecHeight = config.codec_size.height;
5430 meta.presentWidth = config.present_size.width;
5431 meta.presentHeight = config.present_size.height;
5432
5433 meta.profile = config.profile_string;
5434 meta.level = config.level_string;
5435 meta.bitDepth = config.bit_depth;
5436 meta.chromaFormat = config.chroma_format;
5437 meta.sarRatio = config.sar_ratio;
5438 meta.frameRate = config.frame_rate;
5439
5440 if (config.frame_rate.fixed === false || config.frame_rate.fps_num === 0 || config.frame_rate.fps_den === 0) {
5441 meta.frameRate = this._referenceFrameRate;
5442 }
5443
5444 var fps_den = meta.frameRate.fps_den;
5445 var fps_num = meta.frameRate.fps_num;
5446 meta.refSampleDuration = meta.timescale * (fps_den / fps_num);
5447
5448 var codecArray = sps.subarray(1, 4);
5449 var codecString = 'avc1.';
5450 for (var j = 0; j < 3; j++) {
5451 var h = codecArray[j].toString(16);
5452 if (h.length < 2) {
5453 h = '0' + h;
5454 }
5455 codecString += h;
5456 }
5457 meta.codec = codecString;
5458
5459 var mi = this._mediaInfo;
5460 mi.width = meta.codecWidth;
5461 mi.height = meta.codecHeight;
5462 mi.fps = meta.frameRate.fps;
5463 mi.profile = meta.profile;
5464 mi.level = meta.level;
5465 mi.refFrames = config.ref_frames;
5466 mi.chromaFormat = config.chroma_format_string;
5467 mi.sarNum = meta.sarRatio.width;
5468 mi.sarDen = meta.sarRatio.height;
5469 mi.videoCodec = codecString;
5470
5471 if (mi.hasAudio) {
5472 if (mi.audioCodec != null) {
5473 mi.mimeType = 'video/x-flv; codecs="' + mi.videoCodec + ',' + mi.audioCodec + '"';
5474 }
5475 } else {
5476 mi.mimeType = 'video/x-flv; codecs="' + mi.videoCodec + '"';
5477 }
5478 if (mi.isComplete()) {
5479 this._onMediaInfo(mi);
5480 }
5481 }
5482
5483 var ppsCount = v.getUint8(offset); // numOfPictureParameterSets
5484 if (ppsCount === 0) {
5485 this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid AVCDecoderConfigurationRecord: No PPS');
5486 return;
5487 } else if (ppsCount > 1) {
5488 _logger2.default.w(this.TAG, 'Flv: Strange AVCDecoderConfigurationRecord: PPS Count = ' + ppsCount);
5489 }
5490
5491 offset++;
5492
5493 for (var _i = 0; _i < ppsCount; _i++) {
5494 var _len = v.getUint16(offset, !le); // pictureParameterSetLength
5495 offset += 2;
5496
5497 if (_len === 0) {
5498 continue;
5499 }
5500
5501 // pps is useless for extracting video information
5502 offset += _len;
5503 }
5504
5505 meta.avcc = new Uint8Array(dataSize);
5506 meta.avcc.set(new Uint8Array(arrayBuffer, dataOffset, dataSize), 0);
5507 _logger2.default.v(this.TAG, 'Parsed AVCDecoderConfigurationRecord');
5508
5509 if (this._isInitialMetadataDispatched()) {
5510 // flush parsed frames
5511 if (this._dispatch && (this._audioTrack.length || this._videoTrack.length)) {
5512 this._onDataAvailable(this._audioTrack, this._videoTrack);
5513 }
5514 } else {
5515 this._videoInitialMetadataDispatched = true;
5516 }
5517 // notify new metadata
5518 this._dispatch = false;
5519 this._onTrackMetadata('video', meta);
5520 }
5521 }, {
5522 key: '_parseAVCVideoData',
5523 value: function _parseAVCVideoData(arrayBuffer, dataOffset, dataSize, tagTimestamp, tagPosition, frameType, cts) {
5524 var le = this._littleEndian;
5525 var v = new DataView(arrayBuffer, dataOffset, dataSize);
5526
5527 var units = [],
5528 length = 0;
5529
5530 var offset = 0;
5531 var lengthSize = this._naluLengthSize;
5532 var dts = this._timestampBase + tagTimestamp;
5533 var keyframe = frameType === 1; // from FLV Frame Type constants
5534
5535 while (offset < dataSize) {
5536 if (offset + 4 >= dataSize) {
5537 _logger2.default.w(this.TAG, 'Malformed Nalu near timestamp ' + dts + ', offset = ' + offset + ', dataSize = ' + dataSize);
5538 break; // data not enough for next Nalu
5539 }
5540 // Nalu with length-header (AVC1)
5541 var naluSize = v.getUint32(offset, !le); // Big-Endian read
5542 if (lengthSize === 3) {
5543 naluSize >>>= 8;
5544 }
5545 if (naluSize > dataSize - lengthSize) {
5546 _logger2.default.w(this.TAG, 'Malformed Nalus near timestamp ' + dts + ', NaluSize > DataSize!');
5547 return;
5548 }
5549
5550 var unitType = v.getUint8(offset + lengthSize) & 0x1F;
5551
5552 if (unitType === 5) {
5553 // IDR
5554 keyframe = true;
5555 }
5556
5557 var data = new Uint8Array(arrayBuffer, dataOffset + offset, lengthSize + naluSize);
5558 var unit = { type: unitType, data: data };
5559 units.push(unit);
5560 length += data.byteLength;
5561
5562 offset += lengthSize + naluSize;
5563 }
5564
5565 if (units.length) {
5566 var track = this._videoTrack;
5567 var avcSample = {
5568 units: units,
5569 length: length,
5570 isKeyframe: keyframe,
5571 dts: dts,
5572 cts: cts,
5573 pts: dts + cts
5574 };
5575 if (keyframe) {
5576 avcSample.fileposition = tagPosition;
5577 }
5578 track.samples.push(avcSample);
5579 track.length += length;
5580 }
5581 }
5582 }, {
5583 key: 'onTrackMetadata',
5584 get: function get() {
5585 return this._onTrackMetadata;
5586 },
5587 set: function set(callback) {
5588 this._onTrackMetadata = callback;
5589 }
5590
5591 // prototype: function(mediaInfo: MediaInfo): void
5592
5593 }, {
5594 key: 'onMediaInfo',
5595 get: function get() {
5596 return this._onMediaInfo;
5597 },
5598 set: function set(callback) {
5599 this._onMediaInfo = callback;
5600 }
5601 }, {
5602 key: 'onMetaDataArrived',
5603 get: function get() {
5604 return this._onMetaDataArrived;
5605 },
5606 set: function set(callback) {
5607 this._onMetaDataArrived = callback;
5608 }
5609 }, {
5610 key: 'onScriptDataArrived',
5611 get: function get() {
5612 return this._onScriptDataArrived;
5613 },
5614 set: function set(callback) {
5615 this._onScriptDataArrived = callback;
5616 }
5617
5618 // prototype: function(type: number, info: string): void
5619
5620 }, {
5621 key: 'onError',
5622 get: function get() {
5623 return this._onError;
5624 },
5625 set: function set(callback) {
5626 this._onError = callback;
5627 }
5628
5629 // prototype: function(videoTrack: any, audioTrack: any): void
5630
5631 }, {
5632 key: 'onDataAvailable',
5633 get: function get() {
5634 return this._onDataAvailable;
5635 },
5636 set: function set(callback) {
5637 this._onDataAvailable = callback;
5638 }
5639
5640 // timestamp base for output samples, must be in milliseconds
5641
5642 }, {
5643 key: 'timestampBase',
5644 get: function get() {
5645 return this._timestampBase;
5646 },
5647 set: function set(base) {
5648 this._timestampBase = base;
5649 }
5650 }, {
5651 key: 'overridedDuration',
5652 get: function get() {
5653 return this._duration;
5654 }
5655
5656 // Force-override media duration. Must be in milliseconds, int32
5657 ,
5658 set: function set(duration) {
5659 this._durationOverrided = true;
5660 this._duration = duration;
5661 this._mediaInfo.duration = duration;
5662 }
5663
5664 // Force-override audio track present flag, boolean
5665
5666 }, {
5667 key: 'overridedHasAudio',
5668 set: function set(hasAudio) {
5669 this._hasAudioFlagOverrided = true;
5670 this._hasAudio = hasAudio;
5671 this._mediaInfo.hasAudio = hasAudio;
5672 }
5673
5674 // Force-override video track present flag, boolean
5675
5676 }, {
5677 key: 'overridedHasVideo',
5678 set: function set(hasVideo) {
5679 this._hasVideoFlagOverrided = true;
5680 this._hasVideo = hasVideo;
5681 this._mediaInfo.hasVideo = hasVideo;
5682 }
5683 }], [{
5684 key: 'probe',
5685 value: function probe(buffer) {
5686 var data = new Uint8Array(buffer);
5687 var mismatch = { match: false };
5688
5689 if (data[0] !== 0x46 || data[1] !== 0x4C || data[2] !== 0x56 || data[3] !== 0x01) {
5690 return mismatch;
5691 }
5692
5693 var hasAudio = (data[4] & 4) >>> 2 !== 0;
5694 var hasVideo = (data[4] & 1) !== 0;
5695
5696 var offset = ReadBig32(data, 5);
5697
5698 if (offset < 9) {
5699 return mismatch;
5700 }
5701
5702 return {
5703 match: true,
5704 consumed: offset,
5705 dataOffset: offset,
5706 hasAudioTrack: hasAudio,
5707 hasVideoTrack: hasVideo
5708 };
5709 }
5710 }]);
5711
5712 return FLVDemuxer;
5713}();
5714
5715exports.default = FLVDemuxer;
5716
5717},{"../core/media-info.js":7,"../utils/exception.js":40,"../utils/logger.js":41,"./amf-parser.js":15,"./demux-errors.js":16,"./sps-parser.js":19}],19:[function(_dereq_,module,exports){
5718'use strict';
5719
5720Object.defineProperty(exports, "__esModule", {
5721 value: true
5722});
5723
5724var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
5725 * Copyright (C) 2016 Bilibili. All Rights Reserved.
5726 *
5727 * @author zheng qian <xqq@xqq.im>
5728 *
5729 * Licensed under the Apache License, Version 2.0 (the "License");
5730 * you may not use this file except in compliance with the License.
5731 * You may obtain a copy of the License at
5732 *
5733 * http://www.apache.org/licenses/LICENSE-2.0
5734 *
5735 * Unless required by applicable law or agreed to in writing, software
5736 * distributed under the License is distributed on an "AS IS" BASIS,
5737 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5738 * See the License for the specific language governing permissions and
5739 * limitations under the License.
5740 */
5741
5742var _expGolomb = _dereq_('./exp-golomb.js');
5743
5744var _expGolomb2 = _interopRequireDefault(_expGolomb);
5745
5746function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
5747
5748function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5749
5750var SPSParser = function () {
5751 function SPSParser() {
5752 _classCallCheck(this, SPSParser);
5753 }
5754
5755 _createClass(SPSParser, null, [{
5756 key: '_ebsp2rbsp',
5757 value: function _ebsp2rbsp(uint8array) {
5758 var src = uint8array;
5759 var src_length = src.byteLength;
5760 var dst = new Uint8Array(src_length);
5761 var dst_idx = 0;
5762
5763 for (var i = 0; i < src_length; i++) {
5764 if (i >= 2) {
5765 // Unescape: Skip 0x03 after 00 00
5766 if (src[i] === 0x03 && src[i - 1] === 0x00 && src[i - 2] === 0x00) {
5767 continue;
5768 }
5769 }
5770 dst[dst_idx] = src[i];
5771 dst_idx++;
5772 }
5773
5774 return new Uint8Array(dst.buffer, 0, dst_idx);
5775 }
5776 }, {
5777 key: 'parseSPS',
5778 value: function parseSPS(uint8array) {
5779 var rbsp = SPSParser._ebsp2rbsp(uint8array);
5780 var gb = new _expGolomb2.default(rbsp);
5781
5782 gb.readByte();
5783 var profile_idc = gb.readByte(); // profile_idc
5784 gb.readByte(); // constraint_set_flags[5] + reserved_zero[3]
5785 var level_idc = gb.readByte(); // level_idc
5786 gb.readUEG(); // seq_parameter_set_id
5787
5788 var profile_string = SPSParser.getProfileString(profile_idc);
5789 var level_string = SPSParser.getLevelString(level_idc);
5790 var chroma_format_idc = 1;
5791 var chroma_format = 420;
5792 var chroma_format_table = [0, 420, 422, 444];
5793 var bit_depth = 8;
5794
5795 if (profile_idc === 100 || profile_idc === 110 || profile_idc === 122 || profile_idc === 244 || profile_idc === 44 || profile_idc === 83 || profile_idc === 86 || profile_idc === 118 || profile_idc === 128 || profile_idc === 138 || profile_idc === 144) {
5796
5797 chroma_format_idc = gb.readUEG();
5798 if (chroma_format_idc === 3) {
5799 gb.readBits(1); // separate_colour_plane_flag
5800 }
5801 if (chroma_format_idc <= 3) {
5802 chroma_format = chroma_format_table[chroma_format_idc];
5803 }
5804
5805 bit_depth = gb.readUEG() + 8; // bit_depth_luma_minus8
5806 gb.readUEG(); // bit_depth_chroma_minus8
5807 gb.readBits(1); // qpprime_y_zero_transform_bypass_flag
5808 if (gb.readBool()) {
5809 // seq_scaling_matrix_present_flag
5810 var scaling_list_count = chroma_format_idc !== 3 ? 8 : 12;
5811 for (var i = 0; i < scaling_list_count; i++) {
5812 if (gb.readBool()) {
5813 // seq_scaling_list_present_flag
5814 if (i < 6) {
5815 SPSParser._skipScalingList(gb, 16);
5816 } else {
5817 SPSParser._skipScalingList(gb, 64);
5818 }
5819 }
5820 }
5821 }
5822 }
5823 gb.readUEG(); // log2_max_frame_num_minus4
5824 var pic_order_cnt_type = gb.readUEG();
5825 if (pic_order_cnt_type === 0) {
5826 gb.readUEG(); // log2_max_pic_order_cnt_lsb_minus_4
5827 } else if (pic_order_cnt_type === 1) {
5828 gb.readBits(1); // delta_pic_order_always_zero_flag
5829 gb.readSEG(); // offset_for_non_ref_pic
5830 gb.readSEG(); // offset_for_top_to_bottom_field
5831 var num_ref_frames_in_pic_order_cnt_cycle = gb.readUEG();
5832 for (var _i = 0; _i < num_ref_frames_in_pic_order_cnt_cycle; _i++) {
5833 gb.readSEG(); // offset_for_ref_frame
5834 }
5835 }
5836 var ref_frames = gb.readUEG(); // max_num_ref_frames
5837 gb.readBits(1); // gaps_in_frame_num_value_allowed_flag
5838
5839 var pic_width_in_mbs_minus1 = gb.readUEG();
5840 var pic_height_in_map_units_minus1 = gb.readUEG();
5841
5842 var frame_mbs_only_flag = gb.readBits(1);
5843 if (frame_mbs_only_flag === 0) {
5844 gb.readBits(1); // mb_adaptive_frame_field_flag
5845 }
5846 gb.readBits(1); // direct_8x8_inference_flag
5847
5848 var frame_crop_left_offset = 0;
5849 var frame_crop_right_offset = 0;
5850 var frame_crop_top_offset = 0;
5851 var frame_crop_bottom_offset = 0;
5852
5853 var frame_cropping_flag = gb.readBool();
5854 if (frame_cropping_flag) {
5855 frame_crop_left_offset = gb.readUEG();
5856 frame_crop_right_offset = gb.readUEG();
5857 frame_crop_top_offset = gb.readUEG();
5858 frame_crop_bottom_offset = gb.readUEG();
5859 }
5860
5861 var sar_width = 1,
5862 sar_height = 1;
5863 var fps = 0,
5864 fps_fixed = true,
5865 fps_num = 0,
5866 fps_den = 0;
5867
5868 var vui_parameters_present_flag = gb.readBool();
5869 if (vui_parameters_present_flag) {
5870 if (gb.readBool()) {
5871 // aspect_ratio_info_present_flag
5872 var aspect_ratio_idc = gb.readByte();
5873 var sar_w_table = [1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2];
5874 var sar_h_table = [1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1];
5875
5876 if (aspect_ratio_idc > 0 && aspect_ratio_idc < 16) {
5877 sar_width = sar_w_table[aspect_ratio_idc - 1];
5878 sar_height = sar_h_table[aspect_ratio_idc - 1];
5879 } else if (aspect_ratio_idc === 255) {
5880 sar_width = gb.readByte() << 8 | gb.readByte();
5881 sar_height = gb.readByte() << 8 | gb.readByte();
5882 }
5883 }
5884
5885 if (gb.readBool()) {
5886 // overscan_info_present_flag
5887 gb.readBool(); // overscan_appropriate_flag
5888 }
5889 if (gb.readBool()) {
5890 // video_signal_type_present_flag
5891 gb.readBits(4); // video_format & video_full_range_flag
5892 if (gb.readBool()) {
5893 // colour_description_present_flag
5894 gb.readBits(24); // colour_primaries & transfer_characteristics & matrix_coefficients
5895 }
5896 }
5897 if (gb.readBool()) {
5898 // chroma_loc_info_present_flag
5899 gb.readUEG(); // chroma_sample_loc_type_top_field
5900 gb.readUEG(); // chroma_sample_loc_type_bottom_field
5901 }
5902 if (gb.readBool()) {
5903 // timing_info_present_flag
5904 var num_units_in_tick = gb.readBits(32);
5905 var time_scale = gb.readBits(32);
5906 fps_fixed = gb.readBool(); // fixed_frame_rate_flag
5907
5908 fps_num = time_scale;
5909 fps_den = num_units_in_tick * 2;
5910 fps = fps_num / fps_den;
5911 }
5912 }
5913
5914 var sarScale = 1;
5915 if (sar_width !== 1 || sar_height !== 1) {
5916 sarScale = sar_width / sar_height;
5917 }
5918
5919 var crop_unit_x = 0,
5920 crop_unit_y = 0;
5921 if (chroma_format_idc === 0) {
5922 crop_unit_x = 1;
5923 crop_unit_y = 2 - frame_mbs_only_flag;
5924 } else {
5925 var sub_wc = chroma_format_idc === 3 ? 1 : 2;
5926 var sub_hc = chroma_format_idc === 1 ? 2 : 1;
5927 crop_unit_x = sub_wc;
5928 crop_unit_y = sub_hc * (2 - frame_mbs_only_flag);
5929 }
5930
5931 var codec_width = (pic_width_in_mbs_minus1 + 1) * 16;
5932 var codec_height = (2 - frame_mbs_only_flag) * ((pic_height_in_map_units_minus1 + 1) * 16);
5933
5934 codec_width -= (frame_crop_left_offset + frame_crop_right_offset) * crop_unit_x;
5935 codec_height -= (frame_crop_top_offset + frame_crop_bottom_offset) * crop_unit_y;
5936
5937 var present_width = Math.ceil(codec_width * sarScale);
5938
5939 gb.destroy();
5940 gb = null;
5941
5942 return {
5943 profile_string: profile_string, // baseline, high, high10, ...
5944 level_string: level_string, // 3, 3.1, 4, 4.1, 5, 5.1, ...
5945 bit_depth: bit_depth, // 8bit, 10bit, ...
5946 ref_frames: ref_frames,
5947 chroma_format: chroma_format, // 4:2:0, 4:2:2, ...
5948 chroma_format_string: SPSParser.getChromaFormatString(chroma_format),
5949
5950 frame_rate: {
5951 fixed: fps_fixed,
5952 fps: fps,
5953 fps_den: fps_den,
5954 fps_num: fps_num
5955 },
5956
5957 sar_ratio: {
5958 width: sar_width,
5959 height: sar_height
5960 },
5961
5962 codec_size: {
5963 width: codec_width,
5964 height: codec_height
5965 },
5966
5967 present_size: {
5968 width: present_width,
5969 height: codec_height
5970 }
5971 };
5972 }
5973 }, {
5974 key: '_skipScalingList',
5975 value: function _skipScalingList(gb, count) {
5976 var last_scale = 8,
5977 next_scale = 8;
5978 var delta_scale = 0;
5979 for (var i = 0; i < count; i++) {
5980 if (next_scale !== 0) {
5981 delta_scale = gb.readSEG();
5982 next_scale = (last_scale + delta_scale + 256) % 256;
5983 }
5984 last_scale = next_scale === 0 ? last_scale : next_scale;
5985 }
5986 }
5987 }, {
5988 key: 'getProfileString',
5989 value: function getProfileString(profile_idc) {
5990 switch (profile_idc) {
5991 case 66:
5992 return 'Baseline';
5993 case 77:
5994 return 'Main';
5995 case 88:
5996 return 'Extended';
5997 case 100:
5998 return 'High';
5999 case 110:
6000 return 'High10';
6001 case 122:
6002 return 'High422';
6003 case 244:
6004 return 'High444';
6005 default:
6006 return 'Unknown';
6007 }
6008 }
6009 }, {
6010 key: 'getLevelString',
6011 value: function getLevelString(level_idc) {
6012 return (level_idc / 10).toFixed(1);
6013 }
6014 }, {
6015 key: 'getChromaFormatString',
6016 value: function getChromaFormatString(chroma) {
6017 switch (chroma) {
6018 case 420:
6019 return '4:2:0';
6020 case 422:
6021 return '4:2:2';
6022 case 444:
6023 return '4:4:4';
6024 default:
6025 return 'Unknown';
6026 }
6027 }
6028 }]);
6029
6030 return SPSParser;
6031}();
6032
6033exports.default = SPSParser;
6034
6035},{"./exp-golomb.js":17}],20:[function(_dereq_,module,exports){
6036'use strict';
6037
6038Object.defineProperty(exports, "__esModule", {
6039 value: true
6040});
6041
6042var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /*
6043 * Copyright (C) 2016 Bilibili. All Rights Reserved.
6044 *
6045 * @author zheng qian <xqq@xqq.im>
6046 *
6047 * Licensed under the Apache License, Version 2.0 (the "License");
6048 * you may not use this file except in compliance with the License.
6049 * You may obtain a copy of the License at
6050 *
6051 * http://www.apache.org/licenses/LICENSE-2.0
6052 *
6053 * Unless required by applicable law or agreed to in writing, software
6054 * distributed under the License is distributed on an "AS IS" BASIS,
6055 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6056 * See the License for the specific language governing permissions and
6057 * limitations under the License.
6058 */
6059
6060var _polyfill = _dereq_('./utils/polyfill.js');
6061
6062var _polyfill2 = _interopRequireDefault(_polyfill);
6063
6064var _features = _dereq_('./core/features.js');
6065
6066var _features2 = _interopRequireDefault(_features);
6067
6068var _loader = _dereq_('./io/loader.js');
6069
6070var _flvPlayer = _dereq_('./player/flv-player.js');
6071
6072var _flvPlayer2 = _interopRequireDefault(_flvPlayer);
6073
6074var _nativePlayer = _dereq_('./player/native-player.js');
6075
6076var _nativePlayer2 = _interopRequireDefault(_nativePlayer);
6077
6078var _playerEvents = _dereq_('./player/player-events.js');
6079
6080var _playerEvents2 = _interopRequireDefault(_playerEvents);
6081
6082var _playerErrors = _dereq_('./player/player-errors.js');
6083
6084var _loggingControl = _dereq_('./utils/logging-control.js');
6085
6086var _loggingControl2 = _interopRequireDefault(_loggingControl);
6087
6088var _exception = _dereq_('./utils/exception.js');
6089
6090function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
6091
6092// here are all the interfaces
6093
6094// install polyfills
6095_polyfill2.default.install();
6096
6097// factory method
6098function createPlayer(mediaDataSource, optionalConfig) {
6099 var mds = mediaDataSource;
6100 if (mds == null || (typeof mds === 'undefined' ? 'undefined' : _typeof(mds)) !== 'object') {
6101 throw new _exception.InvalidArgumentException('MediaDataSource must be an javascript object!');
6102 }
6103
6104 if (!mds.hasOwnProperty('type')) {
6105 throw new _exception.InvalidArgumentException('MediaDataSource must has type field to indicate video file type!');
6106 }
6107
6108 switch (mds.type) {
6109 case 'flv':
6110 return new _flvPlayer2.default(mds, optionalConfig);
6111 default:
6112 return new _nativePlayer2.default(mds, optionalConfig);
6113 }
6114}
6115
6116// feature detection
6117function isSupported() {
6118 return _features2.default.supportMSEH264Playback();
6119}
6120
6121function getFeatureList() {
6122 return _features2.default.getFeatureList();
6123}
6124
6125// interfaces
6126var flvjs = {};
6127
6128flvjs.createPlayer = createPlayer;
6129flvjs.isSupported = isSupported;
6130flvjs.getFeatureList = getFeatureList;
6131
6132flvjs.BaseLoader = _loader.BaseLoader;
6133flvjs.LoaderStatus = _loader.LoaderStatus;
6134flvjs.LoaderErrors = _loader.LoaderErrors;
6135
6136flvjs.Events = _playerEvents2.default;
6137flvjs.ErrorTypes = _playerErrors.ErrorTypes;
6138flvjs.ErrorDetails = _playerErrors.ErrorDetails;
6139
6140flvjs.FlvPlayer = _flvPlayer2.default;
6141flvjs.NativePlayer = _nativePlayer2.default;
6142flvjs.LoggingControl = _loggingControl2.default;
6143
6144Object.defineProperty(flvjs, 'version', {
6145 enumerable: true,
6146 get: function get() {
6147 // replaced by browserify-versionify transform
6148 return '1.5.0';
6149 }
6150});
6151
6152exports.default = flvjs;
6153
6154},{"./core/features.js":6,"./io/loader.js":24,"./player/flv-player.js":32,"./player/native-player.js":33,"./player/player-errors.js":34,"./player/player-events.js":35,"./utils/exception.js":40,"./utils/logging-control.js":42,"./utils/polyfill.js":43}],21:[function(_dereq_,module,exports){
6155'use strict';
6156
6157// entry/index file
6158
6159// make it compatible with browserify's umd wrapper
6160module.exports = _dereq_('./flv.js').default;
6161
6162},{"./flv.js":20}],22:[function(_dereq_,module,exports){
6163'use strict';
6164
6165Object.defineProperty(exports, "__esModule", {
6166 value: true
6167});
6168
6169var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
6170
6171var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
6172
6173var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
6174
6175var _logger = _dereq_('../utils/logger.js');
6176
6177var _logger2 = _interopRequireDefault(_logger);
6178
6179var _browser = _dereq_('../utils/browser.js');
6180
6181var _browser2 = _interopRequireDefault(_browser);
6182
6183var _loader = _dereq_('./loader.js');
6184
6185var _exception = _dereq_('../utils/exception.js');
6186
6187function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
6188
6189function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6190
6191function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
6192
6193function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
6194 * Copyright (C) 2016 Bilibili. All Rights Reserved.
6195 *
6196 * @author zheng qian <xqq@xqq.im>
6197 *
6198 * Licensed under the Apache License, Version 2.0 (the "License");
6199 * you may not use this file except in compliance with the License.
6200 * You may obtain a copy of the License at
6201 *
6202 * http://www.apache.org/licenses/LICENSE-2.0
6203 *
6204 * Unless required by applicable law or agreed to in writing, software
6205 * distributed under the License is distributed on an "AS IS" BASIS,
6206 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6207 * See the License for the specific language governing permissions and
6208 * limitations under the License.
6209 */
6210
6211/* fetch + stream IO loader. Currently working on chrome 43+.
6212 * fetch provides a better alternative http API to XMLHttpRequest
6213 *
6214 * fetch spec https://fetch.spec.whatwg.org/
6215 * stream spec https://streams.spec.whatwg.org/
6216 */
6217var FetchStreamLoader = function (_BaseLoader) {
6218 _inherits(FetchStreamLoader, _BaseLoader);
6219
6220 _createClass(FetchStreamLoader, null, [{
6221 key: 'isSupported',
6222 value: function isSupported() {
6223 try {
6224 // fetch + stream is broken on Microsoft Edge. Disable before build 15048.
6225 // see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8196907/
6226 // Fixed in Jan 10, 2017. Build 15048+ removed from blacklist.
6227 var isWorkWellEdge = _browser2.default.msedge && _browser2.default.version.minor >= 15048;
6228 var browserNotBlacklisted = _browser2.default.msedge ? isWorkWellEdge : true;
6229 return self.fetch && self.ReadableStream && browserNotBlacklisted;
6230 } catch (e) {
6231 return false;
6232 }
6233 }
6234 }]);
6235
6236 function FetchStreamLoader(seekHandler, config) {
6237 _classCallCheck(this, FetchStreamLoader);
6238
6239 var _this = _possibleConstructorReturn(this, (FetchStreamLoader.__proto__ || Object.getPrototypeOf(FetchStreamLoader)).call(this, 'fetch-stream-loader'));
6240
6241 _this.TAG = 'FetchStreamLoader';
6242
6243 _this._seekHandler = seekHandler;
6244 _this._config = config;
6245 _this._needStash = true;
6246
6247 _this._requestAbort = false;
6248 _this._contentLength = null;
6249 _this._receivedLength = 0;
6250 return _this;
6251 }
6252
6253 _createClass(FetchStreamLoader, [{
6254 key: 'destroy',
6255 value: function destroy() {
6256 if (this.isWorking()) {
6257 this.abort();
6258 }
6259 _get(FetchStreamLoader.prototype.__proto__ || Object.getPrototypeOf(FetchStreamLoader.prototype), 'destroy', this).call(this);
6260 }
6261 }, {
6262 key: 'open',
6263 value: function open(dataSource, range) {
6264 var _this2 = this;
6265
6266 this._dataSource = dataSource;
6267 this._range = range;
6268
6269 var sourceURL = dataSource.url;
6270 if (this._config.reuseRedirectedURL && dataSource.redirectedURL != undefined) {
6271 sourceURL = dataSource.redirectedURL;
6272 }
6273
6274 var seekConfig = this._seekHandler.getConfig(sourceURL, range);
6275
6276 var headers = new self.Headers();
6277
6278 if (_typeof(seekConfig.headers) === 'object') {
6279 var configHeaders = seekConfig.headers;
6280 for (var key in configHeaders) {
6281 if (configHeaders.hasOwnProperty(key)) {
6282 headers.append(key, configHeaders[key]);
6283 }
6284 }
6285 }
6286
6287 var params = {
6288 method: 'GET',
6289 headers: headers,
6290 mode: 'cors',
6291 cache: 'default',
6292 // The default policy of Fetch API in the whatwg standard
6293 // Safari incorrectly indicates 'no-referrer' as default policy, fuck it
6294 referrerPolicy: 'no-referrer-when-downgrade'
6295 };
6296
6297 // add additional headers
6298 if (_typeof(this._config.headers) === 'object') {
6299 for (var _key in this._config.headers) {
6300 headers.append(_key, this._config.headers[_key]);
6301 }
6302 }
6303
6304 // cors is enabled by default
6305 if (dataSource.cors === false) {
6306 // no-cors means 'disregard cors policy', which can only be used in ServiceWorker
6307 params.mode = 'same-origin';
6308 }
6309
6310 // withCredentials is disabled by default
6311 if (dataSource.withCredentials) {
6312 params.credentials = 'include';
6313 }
6314
6315 // referrerPolicy from config
6316 if (dataSource.referrerPolicy) {
6317 params.referrerPolicy = dataSource.referrerPolicy;
6318 }
6319
6320 this._status = _loader.LoaderStatus.kConnecting;
6321 self.fetch(seekConfig.url, params).then(function (res) {
6322 if (_this2._requestAbort) {
6323 _this2._requestAbort = false;
6324 _this2._status = _loader.LoaderStatus.kIdle;
6325 return;
6326 }
6327 if (res.ok && res.status >= 200 && res.status <= 299) {
6328 if (res.url !== seekConfig.url) {
6329 if (_this2._onURLRedirect) {
6330 var redirectedURL = _this2._seekHandler.removeURLParameters(res.url);
6331 _this2._onURLRedirect(redirectedURL);
6332 }
6333 }
6334
6335 var lengthHeader = res.headers.get('Content-Length');
6336 if (lengthHeader != null) {
6337 _this2._contentLength = parseInt(lengthHeader);
6338 if (_this2._contentLength !== 0) {
6339 if (_this2._onContentLengthKnown) {
6340 _this2._onContentLengthKnown(_this2._contentLength);
6341 }
6342 }
6343 }
6344
6345 return _this2._pump.call(_this2, res.body.getReader());
6346 } else {
6347 _this2._status = _loader.LoaderStatus.kError;
6348 if (_this2._onError) {
6349 _this2._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: res.status, msg: res.statusText });
6350 } else {
6351 throw new _exception.RuntimeException('FetchStreamLoader: Http code invalid, ' + res.status + ' ' + res.statusText);
6352 }
6353 }
6354 }).catch(function (e) {
6355 _this2._status = _loader.LoaderStatus.kError;
6356 if (_this2._onError) {
6357 _this2._onError(_loader.LoaderErrors.EXCEPTION, { code: -1, msg: e.message });
6358 } else {
6359 throw e;
6360 }
6361 });
6362 }
6363 }, {
6364 key: 'abort',
6365 value: function abort() {
6366 this._requestAbort = true;
6367 }
6368 }, {
6369 key: '_pump',
6370 value: function _pump(reader) {
6371 var _this3 = this;
6372
6373 // ReadableStreamReader
6374 return reader.read().then(function (result) {
6375 if (result.done) {
6376 // First check received length
6377 if (_this3._contentLength !== null && _this3._receivedLength < _this3._contentLength) {
6378 // Report Early-EOF
6379 _this3._status = _loader.LoaderStatus.kError;
6380 var type = _loader.LoaderErrors.EARLY_EOF;
6381 var info = { code: -1, msg: 'Fetch stream meet Early-EOF' };
6382 if (_this3._onError) {
6383 _this3._onError(type, info);
6384 } else {
6385 throw new _exception.RuntimeException(info.msg);
6386 }
6387 } else {
6388 // OK. Download complete
6389 _this3._status = _loader.LoaderStatus.kComplete;
6390 if (_this3._onComplete) {
6391 _this3._onComplete(_this3._range.from, _this3._range.from + _this3._receivedLength - 1);
6392 }
6393 }
6394 } else {
6395 if (_this3._requestAbort === true) {
6396 _this3._requestAbort = false;
6397 _this3._status = _loader.LoaderStatus.kComplete;
6398 return reader.cancel();
6399 }
6400
6401 _this3._status = _loader.LoaderStatus.kBuffering;
6402
6403 var chunk = result.value.buffer;
6404 var byteStart = _this3._range.from + _this3._receivedLength;
6405 _this3._receivedLength += chunk.byteLength;
6406
6407 if (_this3._onDataArrival) {
6408 _this3._onDataArrival(chunk, byteStart, _this3._receivedLength);
6409 }
6410
6411 _this3._pump(reader);
6412 }
6413 }).catch(function (e) {
6414 if (e.code === 11 && _browser2.default.msedge) {
6415 // InvalidStateError on Microsoft Edge
6416 // Workaround: Edge may throw InvalidStateError after ReadableStreamReader.cancel() call
6417 // Ignore the unknown exception.
6418 // Related issue: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11265202/
6419 return;
6420 }
6421
6422 _this3._status = _loader.LoaderStatus.kError;
6423 var type = 0;
6424 var info = null;
6425
6426 if ((e.code === 19 || e.message === 'network error') && ( // NETWORK_ERR
6427 _this3._contentLength === null || _this3._contentLength !== null && _this3._receivedLength < _this3._contentLength)) {
6428 type = _loader.LoaderErrors.EARLY_EOF;
6429 info = { code: e.code, msg: 'Fetch stream meet Early-EOF' };
6430 } else {
6431 type = _loader.LoaderErrors.EXCEPTION;
6432 info = { code: e.code, msg: e.message };
6433 }
6434
6435 if (_this3._onError) {
6436 _this3._onError(type, info);
6437 } else {
6438 throw new _exception.RuntimeException(info.msg);
6439 }
6440 });
6441 }
6442 }]);
6443
6444 return FetchStreamLoader;
6445}(_loader.BaseLoader);
6446
6447exports.default = FetchStreamLoader;
6448
6449},{"../utils/browser.js":39,"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24}],23:[function(_dereq_,module,exports){
6450'use strict';
6451
6452Object.defineProperty(exports, "__esModule", {
6453 value: true
6454});
6455
6456var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
6457 * Copyright (C) 2016 Bilibili. All Rights Reserved.
6458 *
6459 * @author zheng qian <xqq@xqq.im>
6460 *
6461 * Licensed under the Apache License, Version 2.0 (the "License");
6462 * you may not use this file except in compliance with the License.
6463 * You may obtain a copy of the License at
6464 *
6465 * http://www.apache.org/licenses/LICENSE-2.0
6466 *
6467 * Unless required by applicable law or agreed to in writing, software
6468 * distributed under the License is distributed on an "AS IS" BASIS,
6469 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6470 * See the License for the specific language governing permissions and
6471 * limitations under the License.
6472 */
6473
6474var _logger = _dereq_('../utils/logger.js');
6475
6476var _logger2 = _interopRequireDefault(_logger);
6477
6478var _speedSampler = _dereq_('./speed-sampler.js');
6479
6480var _speedSampler2 = _interopRequireDefault(_speedSampler);
6481
6482var _loader = _dereq_('./loader.js');
6483
6484var _fetchStreamLoader = _dereq_('./fetch-stream-loader.js');
6485
6486var _fetchStreamLoader2 = _interopRequireDefault(_fetchStreamLoader);
6487
6488var _xhrMozChunkedLoader = _dereq_('./xhr-moz-chunked-loader.js');
6489
6490var _xhrMozChunkedLoader2 = _interopRequireDefault(_xhrMozChunkedLoader);
6491
6492var _xhrMsstreamLoader = _dereq_('./xhr-msstream-loader.js');
6493
6494var _xhrMsstreamLoader2 = _interopRequireDefault(_xhrMsstreamLoader);
6495
6496var _xhrRangeLoader = _dereq_('./xhr-range-loader.js');
6497
6498var _xhrRangeLoader2 = _interopRequireDefault(_xhrRangeLoader);
6499
6500var _websocketLoader = _dereq_('./websocket-loader.js');
6501
6502var _websocketLoader2 = _interopRequireDefault(_websocketLoader);
6503
6504var _rangeSeekHandler = _dereq_('./range-seek-handler.js');
6505
6506var _rangeSeekHandler2 = _interopRequireDefault(_rangeSeekHandler);
6507
6508var _paramSeekHandler = _dereq_('./param-seek-handler.js');
6509
6510var _paramSeekHandler2 = _interopRequireDefault(_paramSeekHandler);
6511
6512var _exception = _dereq_('../utils/exception.js');
6513
6514function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
6515
6516function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6517
6518/**
6519 * DataSource: {
6520 * url: string,
6521 * filesize: number,
6522 * cors: boolean,
6523 * withCredentials: boolean
6524 * }
6525 *
6526 */
6527
6528// Manage IO Loaders
6529var IOController = function () {
6530 function IOController(dataSource, config, extraData) {
6531 _classCallCheck(this, IOController);
6532
6533 this.TAG = 'IOController';
6534
6535 this._config = config;
6536 this._extraData = extraData;
6537
6538 this._stashInitialSize = 1024 * 384; // default initial size: 384KB
6539 if (config.stashInitialSize != undefined && config.stashInitialSize > 0) {
6540 // apply from config
6541 this._stashInitialSize = config.stashInitialSize;
6542 }
6543
6544 this._stashUsed = 0;
6545 this._stashSize = this._stashInitialSize;
6546 this._bufferSize = 1024 * 1024 * 3; // initial size: 3MB
6547 this._stashBuffer = new ArrayBuffer(this._bufferSize);
6548 this._stashByteStart = 0;
6549 this._enableStash = true;
6550 if (config.enableStashBuffer === false) {
6551 this._enableStash = false;
6552 }
6553
6554 this._loader = null;
6555 this._loaderClass = null;
6556 this._seekHandler = null;
6557
6558 this._dataSource = dataSource;
6559 this._isWebSocketURL = /wss?:\/\/(.+?)/.test(dataSource.url);
6560 this._refTotalLength = dataSource.filesize ? dataSource.filesize : null;
6561 this._totalLength = this._refTotalLength;
6562 this._fullRequestFlag = false;
6563 this._currentRange = null;
6564 this._redirectedURL = null;
6565
6566 this._speedNormalized = 0;
6567 this._speedSampler = new _speedSampler2.default();
6568 this._speedNormalizeList = [64, 128, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096];
6569
6570 this._isEarlyEofReconnecting = false;
6571
6572 this._paused = false;
6573 this._resumeFrom = 0;
6574
6575 this._onDataArrival = null;
6576 this._onSeeked = null;
6577 this._onError = null;
6578 this._onComplete = null;
6579 this._onRedirect = null;
6580 this._onRecoveredEarlyEof = null;
6581
6582 this._selectSeekHandler();
6583 this._selectLoader();
6584 this._createLoader();
6585 }
6586
6587 _createClass(IOController, [{
6588 key: 'destroy',
6589 value: function destroy() {
6590 if (this._loader.isWorking()) {
6591 this._loader.abort();
6592 }
6593 this._loader.destroy();
6594 this._loader = null;
6595 this._loaderClass = null;
6596 this._dataSource = null;
6597 this._stashBuffer = null;
6598 this._stashUsed = this._stashSize = this._bufferSize = this._stashByteStart = 0;
6599 this._currentRange = null;
6600 this._speedSampler = null;
6601
6602 this._isEarlyEofReconnecting = false;
6603
6604 this._onDataArrival = null;
6605 this._onSeeked = null;
6606 this._onError = null;
6607 this._onComplete = null;
6608 this._onRedirect = null;
6609 this._onRecoveredEarlyEof = null;
6610
6611 this._extraData = null;
6612 }
6613 }, {
6614 key: 'isWorking',
6615 value: function isWorking() {
6616 return this._loader && this._loader.isWorking() && !this._paused;
6617 }
6618 }, {
6619 key: 'isPaused',
6620 value: function isPaused() {
6621 return this._paused;
6622 }
6623 }, {
6624 key: '_selectSeekHandler',
6625 value: function _selectSeekHandler() {
6626 var config = this._config;
6627
6628 if (config.seekType === 'range') {
6629 this._seekHandler = new _rangeSeekHandler2.default(this._config.rangeLoadZeroStart);
6630 } else if (config.seekType === 'param') {
6631 var paramStart = config.seekParamStart || 'bstart';
6632 var paramEnd = config.seekParamEnd || 'bend';
6633
6634 this._seekHandler = new _paramSeekHandler2.default(paramStart, paramEnd);
6635 } else if (config.seekType === 'custom') {
6636 if (typeof config.customSeekHandler !== 'function') {
6637 throw new _exception.InvalidArgumentException('Custom seekType specified in config but invalid customSeekHandler!');
6638 }
6639 this._seekHandler = new config.customSeekHandler();
6640 } else {
6641 throw new _exception.InvalidArgumentException('Invalid seekType in config: ' + config.seekType);
6642 }
6643 }
6644 }, {
6645 key: '_selectLoader',
6646 value: function _selectLoader() {
6647 if (this._config.customLoader != null) {
6648 this._loaderClass = this._config.customLoader;
6649 } else if (this._isWebSocketURL) {
6650 this._loaderClass = _websocketLoader2.default;
6651 } else if (_fetchStreamLoader2.default.isSupported()) {
6652 this._loaderClass = _fetchStreamLoader2.default;
6653 } else if (_xhrMozChunkedLoader2.default.isSupported()) {
6654 this._loaderClass = _xhrMozChunkedLoader2.default;
6655 } else if (_xhrRangeLoader2.default.isSupported()) {
6656 this._loaderClass = _xhrRangeLoader2.default;
6657 } else {
6658 throw new _exception.RuntimeException('Your browser doesn\'t support xhr with arraybuffer responseType!');
6659 }
6660 }
6661 }, {
6662 key: '_createLoader',
6663 value: function _createLoader() {
6664 this._loader = new this._loaderClass(this._seekHandler, this._config);
6665 if (this._loader.needStashBuffer === false) {
6666 this._enableStash = false;
6667 }
6668 this._loader.onContentLengthKnown = this._onContentLengthKnown.bind(this);
6669 this._loader.onURLRedirect = this._onURLRedirect.bind(this);
6670 this._loader.onDataArrival = this._onLoaderChunkArrival.bind(this);
6671 this._loader.onComplete = this._onLoaderComplete.bind(this);
6672 this._loader.onError = this._onLoaderError.bind(this);
6673 }
6674 }, {
6675 key: 'open',
6676 value: function open(optionalFrom) {
6677 this._currentRange = { from: 0, to: -1 };
6678 if (optionalFrom) {
6679 this._currentRange.from = optionalFrom;
6680 }
6681
6682 this._speedSampler.reset();
6683 if (!optionalFrom) {
6684 this._fullRequestFlag = true;
6685 }
6686
6687 this._loader.open(this._dataSource, Object.assign({}, this._currentRange));
6688 }
6689 }, {
6690 key: 'abort',
6691 value: function abort() {
6692 this._loader.abort();
6693
6694 if (this._paused) {
6695 this._paused = false;
6696 this._resumeFrom = 0;
6697 }
6698 }
6699 }, {
6700 key: 'pause',
6701 value: function pause() {
6702 if (this.isWorking()) {
6703 this._loader.abort();
6704
6705 if (this._stashUsed !== 0) {
6706 this._resumeFrom = this._stashByteStart;
6707 this._currentRange.to = this._stashByteStart - 1;
6708 } else {
6709 this._resumeFrom = this._currentRange.to + 1;
6710 }
6711 this._stashUsed = 0;
6712 this._stashByteStart = 0;
6713 this._paused = true;
6714 }
6715 }
6716 }, {
6717 key: 'resume',
6718 value: function resume() {
6719 if (this._paused) {
6720 this._paused = false;
6721 var bytes = this._resumeFrom;
6722 this._resumeFrom = 0;
6723 this._internalSeek(bytes, true);
6724 }
6725 }
6726 }, {
6727 key: 'seek',
6728 value: function seek(bytes) {
6729 this._paused = false;
6730 this._stashUsed = 0;
6731 this._stashByteStart = 0;
6732 this._internalSeek(bytes, true);
6733 }
6734
6735 /**
6736 * When seeking request is from media seeking, unconsumed stash data should be dropped
6737 * However, stash data shouldn't be dropped if seeking requested from http reconnection
6738 *
6739 * @dropUnconsumed: Ignore and discard all unconsumed data in stash buffer
6740 */
6741
6742 }, {
6743 key: '_internalSeek',
6744 value: function _internalSeek(bytes, dropUnconsumed) {
6745 if (this._loader.isWorking()) {
6746 this._loader.abort();
6747 }
6748
6749 // dispatch & flush stash buffer before seek
6750 this._flushStashBuffer(dropUnconsumed);
6751
6752 this._loader.destroy();
6753 this._loader = null;
6754
6755 var requestRange = { from: bytes, to: -1 };
6756 this._currentRange = { from: requestRange.from, to: -1 };
6757
6758 this._speedSampler.reset();
6759 this._stashSize = this._stashInitialSize;
6760 this._createLoader();
6761 this._loader.open(this._dataSource, requestRange);
6762
6763 if (this._onSeeked) {
6764 this._onSeeked();
6765 }
6766 }
6767 }, {
6768 key: 'updateUrl',
6769 value: function updateUrl(url) {
6770 if (!url || typeof url !== 'string' || url.length === 0) {
6771 throw new _exception.InvalidArgumentException('Url must be a non-empty string!');
6772 }
6773
6774 this._dataSource.url = url;
6775
6776 // TODO: replace with new url
6777 }
6778 }, {
6779 key: '_expandBuffer',
6780 value: function _expandBuffer(expectedBytes) {
6781 var bufferNewSize = this._stashSize;
6782 while (bufferNewSize + 1024 * 1024 * 1 < expectedBytes) {
6783 bufferNewSize *= 2;
6784 }
6785
6786 bufferNewSize += 1024 * 1024 * 1; // bufferSize = stashSize + 1MB
6787 if (bufferNewSize === this._bufferSize) {
6788 return;
6789 }
6790
6791 var newBuffer = new ArrayBuffer(bufferNewSize);
6792
6793 if (this._stashUsed > 0) {
6794 // copy existing data into new buffer
6795 var stashOldArray = new Uint8Array(this._stashBuffer, 0, this._stashUsed);
6796 var stashNewArray = new Uint8Array(newBuffer, 0, bufferNewSize);
6797 stashNewArray.set(stashOldArray, 0);
6798 }
6799
6800 this._stashBuffer = newBuffer;
6801 this._bufferSize = bufferNewSize;
6802 }
6803 }, {
6804 key: '_normalizeSpeed',
6805 value: function _normalizeSpeed(input) {
6806 var list = this._speedNormalizeList;
6807 var last = list.length - 1;
6808 var mid = 0;
6809 var lbound = 0;
6810 var ubound = last;
6811
6812 if (input < list[0]) {
6813 return list[0];
6814 }
6815
6816 // binary search
6817 while (lbound <= ubound) {
6818 mid = lbound + Math.floor((ubound - lbound) / 2);
6819 if (mid === last || input >= list[mid] && input < list[mid + 1]) {
6820 return list[mid];
6821 } else if (list[mid] < input) {
6822 lbound = mid + 1;
6823 } else {
6824 ubound = mid - 1;
6825 }
6826 }
6827 }
6828 }, {
6829 key: '_adjustStashSize',
6830 value: function _adjustStashSize(normalized) {
6831 var stashSizeKB = 0;
6832
6833 if (this._config.isLive) {
6834 // live stream: always use single normalized speed for size of stashSizeKB
6835 stashSizeKB = normalized;
6836 } else {
6837 if (normalized < 512) {
6838 stashSizeKB = normalized;
6839 } else if (normalized >= 512 && normalized <= 1024) {
6840 stashSizeKB = Math.floor(normalized * 1.5);
6841 } else {
6842 stashSizeKB = normalized * 2;
6843 }
6844 }
6845
6846 if (stashSizeKB > 8192) {
6847 stashSizeKB = 8192;
6848 }
6849
6850 var bufferSize = stashSizeKB * 1024 + 1024 * 1024 * 1; // stashSize + 1MB
6851 if (this._bufferSize < bufferSize) {
6852 this._expandBuffer(bufferSize);
6853 }
6854 this._stashSize = stashSizeKB * 1024;
6855 }
6856 }, {
6857 key: '_dispatchChunks',
6858 value: function _dispatchChunks(chunks, byteStart) {
6859 this._currentRange.to = byteStart + chunks.byteLength - 1;
6860 return this._onDataArrival(chunks, byteStart);
6861 }
6862 }, {
6863 key: '_onURLRedirect',
6864 value: function _onURLRedirect(redirectedURL) {
6865 this._redirectedURL = redirectedURL;
6866 if (this._onRedirect) {
6867 this._onRedirect(redirectedURL);
6868 }
6869 }
6870 }, {
6871 key: '_onContentLengthKnown',
6872 value: function _onContentLengthKnown(contentLength) {
6873 if (contentLength && this._fullRequestFlag) {
6874 this._totalLength = contentLength;
6875 this._fullRequestFlag = false;
6876 }
6877 }
6878 }, {
6879 key: '_onLoaderChunkArrival',
6880 value: function _onLoaderChunkArrival(chunk, byteStart, receivedLength) {
6881 if (!this._onDataArrival) {
6882 throw new _exception.IllegalStateException('IOController: No existing consumer (onDataArrival) callback!');
6883 }
6884 if (this._paused) {
6885 return;
6886 }
6887 if (this._isEarlyEofReconnecting) {
6888 // Auto-reconnect for EarlyEof succeed, notify to upper-layer by callback
6889 this._isEarlyEofReconnecting = false;
6890 if (this._onRecoveredEarlyEof) {
6891 this._onRecoveredEarlyEof();
6892 }
6893 }
6894
6895 this._speedSampler.addBytes(chunk.byteLength);
6896
6897 // adjust stash buffer size according to network speed dynamically
6898 var KBps = this._speedSampler.lastSecondKBps;
6899 if (KBps !== 0) {
6900 var normalized = this._normalizeSpeed(KBps);
6901 if (this._speedNormalized !== normalized) {
6902 this._speedNormalized = normalized;
6903 this._adjustStashSize(normalized);
6904 }
6905 }
6906
6907 if (!this._enableStash) {
6908 // disable stash
6909 if (this._stashUsed === 0) {
6910 // dispatch chunk directly to consumer;
6911 // check ret value (consumed bytes) and stash unconsumed to stashBuffer
6912 var consumed = this._dispatchChunks(chunk, byteStart);
6913 if (consumed < chunk.byteLength) {
6914 // unconsumed data remain.
6915 var remain = chunk.byteLength - consumed;
6916 if (remain > this._bufferSize) {
6917 this._expandBuffer(remain);
6918 }
6919 var stashArray = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
6920 stashArray.set(new Uint8Array(chunk, consumed), 0);
6921 this._stashUsed += remain;
6922 this._stashByteStart = byteStart + consumed;
6923 }
6924 } else {
6925 // else: Merge chunk into stashBuffer, and dispatch stashBuffer to consumer.
6926 if (this._stashUsed + chunk.byteLength > this._bufferSize) {
6927 this._expandBuffer(this._stashUsed + chunk.byteLength);
6928 }
6929 var _stashArray = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
6930 _stashArray.set(new Uint8Array(chunk), this._stashUsed);
6931 this._stashUsed += chunk.byteLength;
6932 var _consumed = this._dispatchChunks(this._stashBuffer.slice(0, this._stashUsed), this._stashByteStart);
6933 if (_consumed < this._stashUsed && _consumed > 0) {
6934 // unconsumed data remain
6935 var remainArray = new Uint8Array(this._stashBuffer, _consumed);
6936 _stashArray.set(remainArray, 0);
6937 }
6938 this._stashUsed -= _consumed;
6939 this._stashByteStart += _consumed;
6940 }
6941 } else {
6942 // enable stash
6943 if (this._stashUsed === 0 && this._stashByteStart === 0) {
6944 // seeked? or init chunk?
6945 // This is the first chunk after seek action
6946 this._stashByteStart = byteStart;
6947 }
6948 if (this._stashUsed + chunk.byteLength <= this._stashSize) {
6949 // just stash
6950 var _stashArray2 = new Uint8Array(this._stashBuffer, 0, this._stashSize);
6951 _stashArray2.set(new Uint8Array(chunk), this._stashUsed);
6952 this._stashUsed += chunk.byteLength;
6953 } else {
6954 // stashUsed + chunkSize > stashSize, size limit exceeded
6955 var _stashArray3 = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
6956 if (this._stashUsed > 0) {
6957 // There're stash datas in buffer
6958 // dispatch the whole stashBuffer, and stash remain data
6959 // then append chunk to stashBuffer (stash)
6960 var buffer = this._stashBuffer.slice(0, this._stashUsed);
6961 var _consumed2 = this._dispatchChunks(buffer, this._stashByteStart);
6962 if (_consumed2 < buffer.byteLength) {
6963 if (_consumed2 > 0) {
6964 var _remainArray = new Uint8Array(buffer, _consumed2);
6965 _stashArray3.set(_remainArray, 0);
6966 this._stashUsed = _remainArray.byteLength;
6967 this._stashByteStart += _consumed2;
6968 }
6969 } else {
6970 this._stashUsed = 0;
6971 this._stashByteStart += _consumed2;
6972 }
6973 if (this._stashUsed + chunk.byteLength > this._bufferSize) {
6974 this._expandBuffer(this._stashUsed + chunk.byteLength);
6975 _stashArray3 = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
6976 }
6977 _stashArray3.set(new Uint8Array(chunk), this._stashUsed);
6978 this._stashUsed += chunk.byteLength;
6979 } else {
6980 // stash buffer empty, but chunkSize > stashSize (oh, holy shit)
6981 // dispatch chunk directly and stash remain data
6982 var _consumed3 = this._dispatchChunks(chunk, byteStart);
6983 if (_consumed3 < chunk.byteLength) {
6984 var _remain = chunk.byteLength - _consumed3;
6985 if (_remain > this._bufferSize) {
6986 this._expandBuffer(_remain);
6987 _stashArray3 = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
6988 }
6989 _stashArray3.set(new Uint8Array(chunk, _consumed3), 0);
6990 this._stashUsed += _remain;
6991 this._stashByteStart = byteStart + _consumed3;
6992 }
6993 }
6994 }
6995 }
6996 }
6997 }, {
6998 key: '_flushStashBuffer',
6999 value: function _flushStashBuffer(dropUnconsumed) {
7000 if (this._stashUsed > 0) {
7001 var buffer = this._stashBuffer.slice(0, this._stashUsed);
7002 var consumed = this._dispatchChunks(buffer, this._stashByteStart);
7003 var remain = buffer.byteLength - consumed;
7004
7005 if (consumed < buffer.byteLength) {
7006 if (dropUnconsumed) {
7007 _logger2.default.w(this.TAG, remain + ' bytes unconsumed data remain when flush buffer, dropped');
7008 } else {
7009 if (consumed > 0) {
7010 var stashArray = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
7011 var remainArray = new Uint8Array(buffer, consumed);
7012 stashArray.set(remainArray, 0);
7013 this._stashUsed = remainArray.byteLength;
7014 this._stashByteStart += consumed;
7015 }
7016 return 0;
7017 }
7018 }
7019 this._stashUsed = 0;
7020 this._stashByteStart = 0;
7021 return remain;
7022 }
7023 return 0;
7024 }
7025 }, {
7026 key: '_onLoaderComplete',
7027 value: function _onLoaderComplete(from, to) {
7028 // Force-flush stash buffer, and drop unconsumed data
7029 this._flushStashBuffer(true);
7030
7031 if (this._onComplete) {
7032 this._onComplete(this._extraData);
7033 }
7034 }
7035 }, {
7036 key: '_onLoaderError',
7037 value: function _onLoaderError(type, data) {
7038 _logger2.default.e(this.TAG, 'Loader error, code = ' + data.code + ', msg = ' + data.msg);
7039
7040 this._flushStashBuffer(false);
7041
7042 if (this._isEarlyEofReconnecting) {
7043 // Auto-reconnect for EarlyEof failed, throw UnrecoverableEarlyEof error to upper-layer
7044 this._isEarlyEofReconnecting = false;
7045 type = _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF;
7046 }
7047
7048 switch (type) {
7049 case _loader.LoaderErrors.EARLY_EOF:
7050 {
7051 if (!this._config.isLive) {
7052 // Do internal http reconnect if not live stream
7053 if (this._totalLength) {
7054 var nextFrom = this._currentRange.to + 1;
7055 if (nextFrom < this._totalLength) {
7056 _logger2.default.w(this.TAG, 'Connection lost, trying reconnect...');
7057 this._isEarlyEofReconnecting = true;
7058 this._internalSeek(nextFrom, false);
7059 }
7060 return;
7061 }
7062 // else: We don't know totalLength, throw UnrecoverableEarlyEof
7063 }
7064 // live stream: throw UnrecoverableEarlyEof error to upper-layer
7065 type = _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF;
7066 break;
7067 }
7068 case _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF:
7069 case _loader.LoaderErrors.CONNECTING_TIMEOUT:
7070 case _loader.LoaderErrors.HTTP_STATUS_CODE_INVALID:
7071 case _loader.LoaderErrors.EXCEPTION:
7072 break;
7073 }
7074
7075 if (this._onError) {
7076 this._onError(type, data);
7077 } else {
7078 throw new _exception.RuntimeException('IOException: ' + data.msg);
7079 }
7080 }
7081 }, {
7082 key: 'status',
7083 get: function get() {
7084 return this._loader.status;
7085 }
7086 }, {
7087 key: 'extraData',
7088 get: function get() {
7089 return this._extraData;
7090 },
7091 set: function set(data) {
7092 this._extraData = data;
7093 }
7094
7095 // prototype: function onDataArrival(chunks: ArrayBuffer, byteStart: number): number
7096
7097 }, {
7098 key: 'onDataArrival',
7099 get: function get() {
7100 return this._onDataArrival;
7101 },
7102 set: function set(callback) {
7103 this._onDataArrival = callback;
7104 }
7105 }, {
7106 key: 'onSeeked',
7107 get: function get() {
7108 return this._onSeeked;
7109 },
7110 set: function set(callback) {
7111 this._onSeeked = callback;
7112 }
7113
7114 // prototype: function onError(type: number, info: {code: number, msg: string}): void
7115
7116 }, {
7117 key: 'onError',
7118 get: function get() {
7119 return this._onError;
7120 },
7121 set: function set(callback) {
7122 this._onError = callback;
7123 }
7124 }, {
7125 key: 'onComplete',
7126 get: function get() {
7127 return this._onComplete;
7128 },
7129 set: function set(callback) {
7130 this._onComplete = callback;
7131 }
7132 }, {
7133 key: 'onRedirect',
7134 get: function get() {
7135 return this._onRedirect;
7136 },
7137 set: function set(callback) {
7138 this._onRedirect = callback;
7139 }
7140 }, {
7141 key: 'onRecoveredEarlyEof',
7142 get: function get() {
7143 return this._onRecoveredEarlyEof;
7144 },
7145 set: function set(callback) {
7146 this._onRecoveredEarlyEof = callback;
7147 }
7148 }, {
7149 key: 'currentURL',
7150 get: function get() {
7151 return this._dataSource.url;
7152 }
7153 }, {
7154 key: 'hasRedirect',
7155 get: function get() {
7156 return this._redirectedURL != null || this._dataSource.redirectedURL != undefined;
7157 }
7158 }, {
7159 key: 'currentRedirectedURL',
7160 get: function get() {
7161 return this._redirectedURL || this._dataSource.redirectedURL;
7162 }
7163
7164 // in KB/s
7165
7166 }, {
7167 key: 'currentSpeed',
7168 get: function get() {
7169 if (this._loaderClass === _xhrRangeLoader2.default) {
7170 // SpeedSampler is inaccuracy if loader is RangeLoader
7171 return this._loader.currentSpeed;
7172 }
7173 return this._speedSampler.lastSecondKBps;
7174 }
7175 }, {
7176 key: 'loaderType',
7177 get: function get() {
7178 return this._loader.type;
7179 }
7180 }]);
7181
7182 return IOController;
7183}();
7184
7185exports.default = IOController;
7186
7187},{"../utils/exception.js":40,"../utils/logger.js":41,"./fetch-stream-loader.js":22,"./loader.js":24,"./param-seek-handler.js":25,"./range-seek-handler.js":26,"./speed-sampler.js":27,"./websocket-loader.js":28,"./xhr-moz-chunked-loader.js":29,"./xhr-msstream-loader.js":30,"./xhr-range-loader.js":31}],24:[function(_dereq_,module,exports){
7188'use strict';
7189
7190Object.defineProperty(exports, "__esModule", {
7191 value: true
7192});
7193exports.BaseLoader = exports.LoaderErrors = exports.LoaderStatus = undefined;
7194
7195var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
7196 * Copyright (C) 2016 Bilibili. All Rights Reserved.
7197 *
7198 * @author zheng qian <xqq@xqq.im>
7199 *
7200 * Licensed under the Apache License, Version 2.0 (the "License");
7201 * you may not use this file except in compliance with the License.
7202 * You may obtain a copy of the License at
7203 *
7204 * http://www.apache.org/licenses/LICENSE-2.0
7205 *
7206 * Unless required by applicable law or agreed to in writing, software
7207 * distributed under the License is distributed on an "AS IS" BASIS,
7208 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7209 * See the License for the specific language governing permissions and
7210 * limitations under the License.
7211 */
7212
7213var _exception = _dereq_('../utils/exception.js');
7214
7215function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
7216
7217var LoaderStatus = exports.LoaderStatus = {
7218 kIdle: 0,
7219 kConnecting: 1,
7220 kBuffering: 2,
7221 kError: 3,
7222 kComplete: 4
7223};
7224
7225var LoaderErrors = exports.LoaderErrors = {
7226 OK: 'OK',
7227 EXCEPTION: 'Exception',
7228 HTTP_STATUS_CODE_INVALID: 'HttpStatusCodeInvalid',
7229 CONNECTING_TIMEOUT: 'ConnectingTimeout',
7230 EARLY_EOF: 'EarlyEof',
7231 UNRECOVERABLE_EARLY_EOF: 'UnrecoverableEarlyEof'
7232};
7233
7234/* Loader has callbacks which have following prototypes:
7235 * function onContentLengthKnown(contentLength: number): void
7236 * function onURLRedirect(url: string): void
7237 * function onDataArrival(chunk: ArrayBuffer, byteStart: number, receivedLength: number): void
7238 * function onError(errorType: number, errorInfo: {code: number, msg: string}): void
7239 * function onComplete(rangeFrom: number, rangeTo: number): void
7240 */
7241
7242var BaseLoader = exports.BaseLoader = function () {
7243 function BaseLoader(typeName) {
7244 _classCallCheck(this, BaseLoader);
7245
7246 this._type = typeName || 'undefined';
7247 this._status = LoaderStatus.kIdle;
7248 this._needStash = false;
7249 // callbacks
7250 this._onContentLengthKnown = null;
7251 this._onURLRedirect = null;
7252 this._onDataArrival = null;
7253 this._onError = null;
7254 this._onComplete = null;
7255 }
7256
7257 _createClass(BaseLoader, [{
7258 key: 'destroy',
7259 value: function destroy() {
7260 this._status = LoaderStatus.kIdle;
7261 this._onContentLengthKnown = null;
7262 this._onURLRedirect = null;
7263 this._onDataArrival = null;
7264 this._onError = null;
7265 this._onComplete = null;
7266 }
7267 }, {
7268 key: 'isWorking',
7269 value: function isWorking() {
7270 return this._status === LoaderStatus.kConnecting || this._status === LoaderStatus.kBuffering;
7271 }
7272 }, {
7273 key: 'open',
7274
7275
7276 // pure virtual
7277 value: function open(dataSource, range) {
7278 throw new _exception.NotImplementedException('Unimplemented abstract function!');
7279 }
7280 }, {
7281 key: 'abort',
7282 value: function abort() {
7283 throw new _exception.NotImplementedException('Unimplemented abstract function!');
7284 }
7285 }, {
7286 key: 'type',
7287 get: function get() {
7288 return this._type;
7289 }
7290 }, {
7291 key: 'status',
7292 get: function get() {
7293 return this._status;
7294 }
7295 }, {
7296 key: 'needStashBuffer',
7297 get: function get() {
7298 return this._needStash;
7299 }
7300 }, {
7301 key: 'onContentLengthKnown',
7302 get: function get() {
7303 return this._onContentLengthKnown;
7304 },
7305 set: function set(callback) {
7306 this._onContentLengthKnown = callback;
7307 }
7308 }, {
7309 key: 'onURLRedirect',
7310 get: function get() {
7311 return this._onURLRedirect;
7312 },
7313 set: function set(callback) {
7314 this._onURLRedirect = callback;
7315 }
7316 }, {
7317 key: 'onDataArrival',
7318 get: function get() {
7319 return this._onDataArrival;
7320 },
7321 set: function set(callback) {
7322 this._onDataArrival = callback;
7323 }
7324 }, {
7325 key: 'onError',
7326 get: function get() {
7327 return this._onError;
7328 },
7329 set: function set(callback) {
7330 this._onError = callback;
7331 }
7332 }, {
7333 key: 'onComplete',
7334 get: function get() {
7335 return this._onComplete;
7336 },
7337 set: function set(callback) {
7338 this._onComplete = callback;
7339 }
7340 }]);
7341
7342 return BaseLoader;
7343}();
7344
7345},{"../utils/exception.js":40}],25:[function(_dereq_,module,exports){
7346'use strict';
7347
7348Object.defineProperty(exports, "__esModule", {
7349 value: true
7350});
7351
7352var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
7353
7354function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
7355
7356/*
7357 * Copyright (C) 2016 Bilibili. All Rights Reserved.
7358 *
7359 * @author zheng qian <xqq@xqq.im>
7360 *
7361 * Licensed under the Apache License, Version 2.0 (the "License");
7362 * you may not use this file except in compliance with the License.
7363 * You may obtain a copy of the License at
7364 *
7365 * http://www.apache.org/licenses/LICENSE-2.0
7366 *
7367 * Unless required by applicable law or agreed to in writing, software
7368 * distributed under the License is distributed on an "AS IS" BASIS,
7369 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7370 * See the License for the specific language governing permissions and
7371 * limitations under the License.
7372 */
7373
7374var ParamSeekHandler = function () {
7375 function ParamSeekHandler(paramStart, paramEnd) {
7376 _classCallCheck(this, ParamSeekHandler);
7377
7378 this._startName = paramStart;
7379 this._endName = paramEnd;
7380 }
7381
7382 _createClass(ParamSeekHandler, [{
7383 key: 'getConfig',
7384 value: function getConfig(baseUrl, range) {
7385 var url = baseUrl;
7386
7387 if (range.from !== 0 || range.to !== -1) {
7388 var needAnd = true;
7389 if (url.indexOf('?') === -1) {
7390 url += '?';
7391 needAnd = false;
7392 }
7393
7394 if (needAnd) {
7395 url += '&';
7396 }
7397
7398 url += this._startName + '=' + range.from.toString();
7399
7400 if (range.to !== -1) {
7401 url += '&' + this._endName + '=' + range.to.toString();
7402 }
7403 }
7404
7405 return {
7406 url: url,
7407 headers: {}
7408 };
7409 }
7410 }, {
7411 key: 'removeURLParameters',
7412 value: function removeURLParameters(seekedURL) {
7413 var baseURL = seekedURL.split('?')[0];
7414 var params = undefined;
7415
7416 var queryIndex = seekedURL.indexOf('?');
7417 if (queryIndex !== -1) {
7418 params = seekedURL.substring(queryIndex + 1);
7419 }
7420
7421 var resultParams = '';
7422
7423 if (params != undefined && params.length > 0) {
7424 var pairs = params.split('&');
7425
7426 for (var i = 0; i < pairs.length; i++) {
7427 var pair = pairs[i].split('=');
7428 var requireAnd = i > 0;
7429
7430 if (pair[0] !== this._startName && pair[0] !== this._endName) {
7431 if (requireAnd) {
7432 resultParams += '&';
7433 }
7434 resultParams += pairs[i];
7435 }
7436 }
7437 }
7438
7439 return resultParams.length === 0 ? baseURL : baseURL + '?' + resultParams;
7440 }
7441 }]);
7442
7443 return ParamSeekHandler;
7444}();
7445
7446exports.default = ParamSeekHandler;
7447
7448},{}],26:[function(_dereq_,module,exports){
7449'use strict';
7450
7451Object.defineProperty(exports, "__esModule", {
7452 value: true
7453});
7454
7455var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
7456
7457function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
7458
7459/*
7460 * Copyright (C) 2016 Bilibili. All Rights Reserved.
7461 *
7462 * @author zheng qian <xqq@xqq.im>
7463 *
7464 * Licensed under the Apache License, Version 2.0 (the "License");
7465 * you may not use this file except in compliance with the License.
7466 * You may obtain a copy of the License at
7467 *
7468 * http://www.apache.org/licenses/LICENSE-2.0
7469 *
7470 * Unless required by applicable law or agreed to in writing, software
7471 * distributed under the License is distributed on an "AS IS" BASIS,
7472 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7473 * See the License for the specific language governing permissions and
7474 * limitations under the License.
7475 */
7476
7477var RangeSeekHandler = function () {
7478 function RangeSeekHandler(zeroStart) {
7479 _classCallCheck(this, RangeSeekHandler);
7480
7481 this._zeroStart = zeroStart || false;
7482 }
7483
7484 _createClass(RangeSeekHandler, [{
7485 key: 'getConfig',
7486 value: function getConfig(url, range) {
7487 var headers = {};
7488
7489 if (range.from !== 0 || range.to !== -1) {
7490 var param = void 0;
7491 if (range.to !== -1) {
7492 param = 'bytes=' + range.from.toString() + '-' + range.to.toString();
7493 } else {
7494 param = 'bytes=' + range.from.toString() + '-';
7495 }
7496 headers['Range'] = param;
7497 } else if (this._zeroStart) {
7498 headers['Range'] = 'bytes=0-';
7499 }
7500
7501 return {
7502 url: url,
7503 headers: headers
7504 };
7505 }
7506 }, {
7507 key: 'removeURLParameters',
7508 value: function removeURLParameters(seekedURL) {
7509 return seekedURL;
7510 }
7511 }]);
7512
7513 return RangeSeekHandler;
7514}();
7515
7516exports.default = RangeSeekHandler;
7517
7518},{}],27:[function(_dereq_,module,exports){
7519"use strict";
7520
7521Object.defineProperty(exports, "__esModule", {
7522 value: true
7523});
7524
7525var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
7526
7527function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
7528
7529/*
7530 * Copyright (C) 2016 Bilibili. All Rights Reserved.
7531 *
7532 * @author zheng qian <xqq@xqq.im>
7533 *
7534 * Licensed under the Apache License, Version 2.0 (the "License");
7535 * you may not use this file except in compliance with the License.
7536 * You may obtain a copy of the License at
7537 *
7538 * http://www.apache.org/licenses/LICENSE-2.0
7539 *
7540 * Unless required by applicable law or agreed to in writing, software
7541 * distributed under the License is distributed on an "AS IS" BASIS,
7542 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7543 * See the License for the specific language governing permissions and
7544 * limitations under the License.
7545 */
7546
7547// Utility class to calculate realtime network I/O speed
7548var SpeedSampler = function () {
7549 function SpeedSampler() {
7550 _classCallCheck(this, SpeedSampler);
7551
7552 // milliseconds
7553 this._firstCheckpoint = 0;
7554 this._lastCheckpoint = 0;
7555 this._intervalBytes = 0;
7556 this._totalBytes = 0;
7557 this._lastSecondBytes = 0;
7558
7559 // compatibility detection
7560 if (self.performance && self.performance.now) {
7561 this._now = self.performance.now.bind(self.performance);
7562 } else {
7563 this._now = Date.now;
7564 }
7565 }
7566
7567 _createClass(SpeedSampler, [{
7568 key: "reset",
7569 value: function reset() {
7570 this._firstCheckpoint = this._lastCheckpoint = 0;
7571 this._totalBytes = this._intervalBytes = 0;
7572 this._lastSecondBytes = 0;
7573 }
7574 }, {
7575 key: "addBytes",
7576 value: function addBytes(bytes) {
7577 if (this._firstCheckpoint === 0) {
7578 this._firstCheckpoint = this._now();
7579 this._lastCheckpoint = this._firstCheckpoint;
7580 this._intervalBytes += bytes;
7581 this._totalBytes += bytes;
7582 } else if (this._now() - this._lastCheckpoint < 1000) {
7583 this._intervalBytes += bytes;
7584 this._totalBytes += bytes;
7585 } else {
7586 // duration >= 1000
7587 this._lastSecondBytes = this._intervalBytes;
7588 this._intervalBytes = bytes;
7589 this._totalBytes += bytes;
7590 this._lastCheckpoint = this._now();
7591 }
7592 }
7593 }, {
7594 key: "currentKBps",
7595 get: function get() {
7596 this.addBytes(0);
7597
7598 var durationSeconds = (this._now() - this._lastCheckpoint) / 1000;
7599 if (durationSeconds == 0) durationSeconds = 1;
7600 return this._intervalBytes / durationSeconds / 1024;
7601 }
7602 }, {
7603 key: "lastSecondKBps",
7604 get: function get() {
7605 this.addBytes(0);
7606
7607 if (this._lastSecondBytes !== 0) {
7608 return this._lastSecondBytes / 1024;
7609 } else {
7610 // lastSecondBytes === 0
7611 if (this._now() - this._lastCheckpoint >= 500) {
7612 // if time interval since last checkpoint has exceeded 500ms
7613 // the speed is nearly accurate
7614 return this.currentKBps;
7615 } else {
7616 // We don't know
7617 return 0;
7618 }
7619 }
7620 }
7621 }, {
7622 key: "averageKBps",
7623 get: function get() {
7624 var durationSeconds = (this._now() - this._firstCheckpoint) / 1000;
7625 return this._totalBytes / durationSeconds / 1024;
7626 }
7627 }]);
7628
7629 return SpeedSampler;
7630}();
7631
7632exports.default = SpeedSampler;
7633
7634},{}],28:[function(_dereq_,module,exports){
7635'use strict';
7636
7637Object.defineProperty(exports, "__esModule", {
7638 value: true
7639});
7640
7641var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
7642
7643var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
7644
7645var _logger = _dereq_('../utils/logger.js');
7646
7647var _logger2 = _interopRequireDefault(_logger);
7648
7649var _loader = _dereq_('./loader.js');
7650
7651var _exception = _dereq_('../utils/exception.js');
7652
7653function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
7654
7655function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
7656
7657function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
7658
7659function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
7660 * Copyright (C) 2016 Bilibili. All Rights Reserved.
7661 *
7662 * @author zheng qian <xqq@xqq.im>
7663 *
7664 * Licensed under the Apache License, Version 2.0 (the "License");
7665 * you may not use this file except in compliance with the License.
7666 * You may obtain a copy of the License at
7667 *
7668 * http://www.apache.org/licenses/LICENSE-2.0
7669 *
7670 * Unless required by applicable law or agreed to in writing, software
7671 * distributed under the License is distributed on an "AS IS" BASIS,
7672 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7673 * See the License for the specific language governing permissions and
7674 * limitations under the License.
7675 */
7676
7677// For FLV over WebSocket live stream
7678var WebSocketLoader = function (_BaseLoader) {
7679 _inherits(WebSocketLoader, _BaseLoader);
7680
7681 _createClass(WebSocketLoader, null, [{
7682 key: 'isSupported',
7683 value: function isSupported() {
7684 try {
7685 return typeof self.WebSocket !== 'undefined';
7686 } catch (e) {
7687 return false;
7688 }
7689 }
7690 }]);
7691
7692 function WebSocketLoader() {
7693 _classCallCheck(this, WebSocketLoader);
7694
7695 var _this = _possibleConstructorReturn(this, (WebSocketLoader.__proto__ || Object.getPrototypeOf(WebSocketLoader)).call(this, 'websocket-loader'));
7696
7697 _this.TAG = 'WebSocketLoader';
7698
7699 _this._needStash = true;
7700
7701 _this._ws = null;
7702 _this._requestAbort = false;
7703 _this._receivedLength = 0;
7704 return _this;
7705 }
7706
7707 _createClass(WebSocketLoader, [{
7708 key: 'destroy',
7709 value: function destroy() {
7710 if (this._ws) {
7711 this.abort();
7712 }
7713 _get(WebSocketLoader.prototype.__proto__ || Object.getPrototypeOf(WebSocketLoader.prototype), 'destroy', this).call(this);
7714 }
7715 }, {
7716 key: 'open',
7717 value: function open(dataSource) {
7718 try {
7719 var ws = this._ws = new self.WebSocket(dataSource.url);
7720 ws.binaryType = 'arraybuffer';
7721 ws.onopen = this._onWebSocketOpen.bind(this);
7722 ws.onclose = this._onWebSocketClose.bind(this);
7723 ws.onmessage = this._onWebSocketMessage.bind(this);
7724 ws.onerror = this._onWebSocketError.bind(this);
7725
7726 this._status = _loader.LoaderStatus.kConnecting;
7727 } catch (e) {
7728 this._status = _loader.LoaderStatus.kError;
7729
7730 var info = { code: e.code, msg: e.message };
7731
7732 if (this._onError) {
7733 this._onError(_loader.LoaderErrors.EXCEPTION, info);
7734 } else {
7735 throw new _exception.RuntimeException(info.msg);
7736 }
7737 }
7738 }
7739 }, {
7740 key: 'abort',
7741 value: function abort() {
7742 var ws = this._ws;
7743 if (ws && (ws.readyState === 0 || ws.readyState === 1)) {
7744 // CONNECTING || OPEN
7745 this._requestAbort = true;
7746 ws.close();
7747 }
7748
7749 this._ws = null;
7750 this._status = _loader.LoaderStatus.kComplete;
7751 }
7752 }, {
7753 key: '_onWebSocketOpen',
7754 value: function _onWebSocketOpen(e) {
7755 this._status = _loader.LoaderStatus.kBuffering;
7756 }
7757 }, {
7758 key: '_onWebSocketClose',
7759 value: function _onWebSocketClose(e) {
7760 if (this._requestAbort === true) {
7761 this._requestAbort = false;
7762 return;
7763 }
7764
7765 this._status = _loader.LoaderStatus.kComplete;
7766
7767 if (this._onComplete) {
7768 this._onComplete(0, this._receivedLength - 1);
7769 }
7770 }
7771 }, {
7772 key: '_onWebSocketMessage',
7773 value: function _onWebSocketMessage(e) {
7774 var _this2 = this;
7775
7776 if (e.data instanceof ArrayBuffer) {
7777 this._dispatchArrayBuffer(e.data);
7778 } else if (e.data instanceof Blob) {
7779 var reader = new FileReader();
7780 reader.onload = function () {
7781 _this2._dispatchArrayBuffer(reader.result);
7782 };
7783 reader.readAsArrayBuffer(e.data);
7784 } else {
7785 this._status = _loader.LoaderStatus.kError;
7786 var info = { code: -1, msg: 'Unsupported WebSocket message type: ' + e.data.constructor.name };
7787
7788 if (this._onError) {
7789 this._onError(_loader.LoaderErrors.EXCEPTION, info);
7790 } else {
7791 throw new _exception.RuntimeException(info.msg);
7792 }
7793 }
7794 }
7795 }, {
7796 key: '_dispatchArrayBuffer',
7797 value: function _dispatchArrayBuffer(arraybuffer) {
7798 var chunk = arraybuffer;
7799 var byteStart = this._receivedLength;
7800 this._receivedLength += chunk.byteLength;
7801
7802 if (this._onDataArrival) {
7803 this._onDataArrival(chunk, byteStart, this._receivedLength);
7804 }
7805 }
7806 }, {
7807 key: '_onWebSocketError',
7808 value: function _onWebSocketError(e) {
7809 this._status = _loader.LoaderStatus.kError;
7810
7811 var info = {
7812 code: e.code,
7813 msg: e.message
7814 };
7815
7816 if (this._onError) {
7817 this._onError(_loader.LoaderErrors.EXCEPTION, info);
7818 } else {
7819 throw new _exception.RuntimeException(info.msg);
7820 }
7821 }
7822 }]);
7823
7824 return WebSocketLoader;
7825}(_loader.BaseLoader);
7826
7827exports.default = WebSocketLoader;
7828
7829},{"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24}],29:[function(_dereq_,module,exports){
7830'use strict';
7831
7832Object.defineProperty(exports, "__esModule", {
7833 value: true
7834});
7835
7836var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
7837
7838var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
7839
7840var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
7841
7842var _logger = _dereq_('../utils/logger.js');
7843
7844var _logger2 = _interopRequireDefault(_logger);
7845
7846var _loader = _dereq_('./loader.js');
7847
7848var _exception = _dereq_('../utils/exception.js');
7849
7850function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
7851
7852function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
7853
7854function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
7855
7856function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
7857 * Copyright (C) 2016 Bilibili. All Rights Reserved.
7858 *
7859 * @author zheng qian <xqq@xqq.im>
7860 *
7861 * Licensed under the Apache License, Version 2.0 (the "License");
7862 * you may not use this file except in compliance with the License.
7863 * You may obtain a copy of the License at
7864 *
7865 * http://www.apache.org/licenses/LICENSE-2.0
7866 *
7867 * Unless required by applicable law or agreed to in writing, software
7868 * distributed under the License is distributed on an "AS IS" BASIS,
7869 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7870 * See the License for the specific language governing permissions and
7871 * limitations under the License.
7872 */
7873
7874// For FireFox browser which supports `xhr.responseType = 'moz-chunked-arraybuffer'`
7875var MozChunkedLoader = function (_BaseLoader) {
7876 _inherits(MozChunkedLoader, _BaseLoader);
7877
7878 _createClass(MozChunkedLoader, null, [{
7879 key: 'isSupported',
7880 value: function isSupported() {
7881 try {
7882 var xhr = new XMLHttpRequest();
7883 // Firefox 37- requires .open() to be called before setting responseType
7884 xhr.open('GET', 'https://example.com', true);
7885 xhr.responseType = 'moz-chunked-arraybuffer';
7886 return xhr.responseType === 'moz-chunked-arraybuffer';
7887 } catch (e) {
7888 _logger2.default.w('MozChunkedLoader', e.message);
7889 return false;
7890 }
7891 }
7892 }]);
7893
7894 function MozChunkedLoader(seekHandler, config) {
7895 _classCallCheck(this, MozChunkedLoader);
7896
7897 var _this = _possibleConstructorReturn(this, (MozChunkedLoader.__proto__ || Object.getPrototypeOf(MozChunkedLoader)).call(this, 'xhr-moz-chunked-loader'));
7898
7899 _this.TAG = 'MozChunkedLoader';
7900
7901 _this._seekHandler = seekHandler;
7902 _this._config = config;
7903 _this._needStash = true;
7904
7905 _this._xhr = null;
7906 _this._requestAbort = false;
7907 _this._contentLength = null;
7908 _this._receivedLength = 0;
7909 return _this;
7910 }
7911
7912 _createClass(MozChunkedLoader, [{
7913 key: 'destroy',
7914 value: function destroy() {
7915 if (this.isWorking()) {
7916 this.abort();
7917 }
7918 if (this._xhr) {
7919 this._xhr.onreadystatechange = null;
7920 this._xhr.onprogress = null;
7921 this._xhr.onloadend = null;
7922 this._xhr.onerror = null;
7923 this._xhr = null;
7924 }
7925 _get(MozChunkedLoader.prototype.__proto__ || Object.getPrototypeOf(MozChunkedLoader.prototype), 'destroy', this).call(this);
7926 }
7927 }, {
7928 key: 'open',
7929 value: function open(dataSource, range) {
7930 this._dataSource = dataSource;
7931 this._range = range;
7932
7933 var sourceURL = dataSource.url;
7934 if (this._config.reuseRedirectedURL && dataSource.redirectedURL != undefined) {
7935 sourceURL = dataSource.redirectedURL;
7936 }
7937
7938 var seekConfig = this._seekHandler.getConfig(sourceURL, range);
7939 this._requestURL = seekConfig.url;
7940
7941 var xhr = this._xhr = new XMLHttpRequest();
7942 xhr.open('GET', seekConfig.url, true);
7943 xhr.responseType = 'moz-chunked-arraybuffer';
7944 xhr.onreadystatechange = this._onReadyStateChange.bind(this);
7945 xhr.onprogress = this._onProgress.bind(this);
7946 xhr.onloadend = this._onLoadEnd.bind(this);
7947 xhr.onerror = this._onXhrError.bind(this);
7948
7949 // cors is auto detected and enabled by xhr
7950
7951 // withCredentials is disabled by default
7952 if (dataSource.withCredentials) {
7953 xhr.withCredentials = true;
7954 }
7955
7956 if (_typeof(seekConfig.headers) === 'object') {
7957 var headers = seekConfig.headers;
7958
7959 for (var key in headers) {
7960 if (headers.hasOwnProperty(key)) {
7961 xhr.setRequestHeader(key, headers[key]);
7962 }
7963 }
7964 }
7965
7966 // add additional headers
7967 if (_typeof(this._config.headers) === 'object') {
7968 var _headers = this._config.headers;
7969
7970 for (var _key in _headers) {
7971 if (_headers.hasOwnProperty(_key)) {
7972 xhr.setRequestHeader(_key, _headers[_key]);
7973 }
7974 }
7975 }
7976
7977 this._status = _loader.LoaderStatus.kConnecting;
7978 xhr.send();
7979 }
7980 }, {
7981 key: 'abort',
7982 value: function abort() {
7983 this._requestAbort = true;
7984 if (this._xhr) {
7985 this._xhr.abort();
7986 }
7987 this._status = _loader.LoaderStatus.kComplete;
7988 }
7989 }, {
7990 key: '_onReadyStateChange',
7991 value: function _onReadyStateChange(e) {
7992 var xhr = e.target;
7993
7994 if (xhr.readyState === 2) {
7995 // HEADERS_RECEIVED
7996 if (xhr.responseURL != undefined && xhr.responseURL !== this._requestURL) {
7997 if (this._onURLRedirect) {
7998 var redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
7999 this._onURLRedirect(redirectedURL);
8000 }
8001 }
8002
8003 if (xhr.status !== 0 && (xhr.status < 200 || xhr.status > 299)) {
8004 this._status = _loader.LoaderStatus.kError;
8005 if (this._onError) {
8006 this._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: xhr.status, msg: xhr.statusText });
8007 } else {
8008 throw new _exception.RuntimeException('MozChunkedLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
8009 }
8010 } else {
8011 this._status = _loader.LoaderStatus.kBuffering;
8012 }
8013 }
8014 }
8015 }, {
8016 key: '_onProgress',
8017 value: function _onProgress(e) {
8018 if (this._status === _loader.LoaderStatus.kError) {
8019 // Ignore error response
8020 return;
8021 }
8022
8023 if (this._contentLength === null) {
8024 if (e.total !== null && e.total !== 0) {
8025 this._contentLength = e.total;
8026 if (this._onContentLengthKnown) {
8027 this._onContentLengthKnown(this._contentLength);
8028 }
8029 }
8030 }
8031
8032 var chunk = e.target.response;
8033 var byteStart = this._range.from + this._receivedLength;
8034 this._receivedLength += chunk.byteLength;
8035
8036 if (this._onDataArrival) {
8037 this._onDataArrival(chunk, byteStart, this._receivedLength);
8038 }
8039 }
8040 }, {
8041 key: '_onLoadEnd',
8042 value: function _onLoadEnd(e) {
8043 if (this._requestAbort === true) {
8044 this._requestAbort = false;
8045 return;
8046 } else if (this._status === _loader.LoaderStatus.kError) {
8047 return;
8048 }
8049
8050 this._status = _loader.LoaderStatus.kComplete;
8051 if (this._onComplete) {
8052 this._onComplete(this._range.from, this._range.from + this._receivedLength - 1);
8053 }
8054 }
8055 }, {
8056 key: '_onXhrError',
8057 value: function _onXhrError(e) {
8058 this._status = _loader.LoaderStatus.kError;
8059 var type = 0;
8060 var info = null;
8061
8062 if (this._contentLength && e.loaded < this._contentLength) {
8063 type = _loader.LoaderErrors.EARLY_EOF;
8064 info = { code: -1, msg: 'Moz-Chunked stream meet Early-Eof' };
8065 } else {
8066 type = _loader.LoaderErrors.EXCEPTION;
8067 info = { code: -1, msg: e.constructor.name + ' ' + e.type };
8068 }
8069
8070 if (this._onError) {
8071 this._onError(type, info);
8072 } else {
8073 throw new _exception.RuntimeException(info.msg);
8074 }
8075 }
8076 }]);
8077
8078 return MozChunkedLoader;
8079}(_loader.BaseLoader);
8080
8081exports.default = MozChunkedLoader;
8082
8083},{"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24}],30:[function(_dereq_,module,exports){
8084'use strict';
8085
8086Object.defineProperty(exports, "__esModule", {
8087 value: true
8088});
8089
8090var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
8091
8092var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
8093
8094var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8095
8096var _logger = _dereq_('../utils/logger.js');
8097
8098var _logger2 = _interopRequireDefault(_logger);
8099
8100var _loader = _dereq_('./loader.js');
8101
8102var _exception = _dereq_('../utils/exception.js');
8103
8104function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8105
8106function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8107
8108function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
8109
8110function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
8111 * Copyright (C) 2016 Bilibili. All Rights Reserved.
8112 *
8113 * @author zheng qian <xqq@xqq.im>
8114 *
8115 * Licensed under the Apache License, Version 2.0 (the "License");
8116 * you may not use this file except in compliance with the License.
8117 * You may obtain a copy of the License at
8118 *
8119 * http://www.apache.org/licenses/LICENSE-2.0
8120 *
8121 * Unless required by applicable law or agreed to in writing, software
8122 * distributed under the License is distributed on an "AS IS" BASIS,
8123 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8124 * See the License for the specific language governing permissions and
8125 * limitations under the License.
8126 */
8127
8128/* Notice: ms-stream may cause IE/Edge browser crash if seek too frequently!!!
8129 * The browser may crash in wininet.dll. Disable for now.
8130 *
8131 * For IE11/Edge browser by microsoft which supports `xhr.responseType = 'ms-stream'`
8132 * Notice that ms-stream API sucks. The buffer is always expanding along with downloading.
8133 *
8134 * We need to abort the xhr if buffer size exceeded limit size (e.g. 16 MiB), then do reconnect.
8135 * in order to release previous ArrayBuffer to avoid memory leak
8136 *
8137 * Otherwise, the ArrayBuffer will increase to a terrible size that equals final file size.
8138 */
8139var MSStreamLoader = function (_BaseLoader) {
8140 _inherits(MSStreamLoader, _BaseLoader);
8141
8142 _createClass(MSStreamLoader, null, [{
8143 key: 'isSupported',
8144 value: function isSupported() {
8145 try {
8146 if (typeof self.MSStream === 'undefined' || typeof self.MSStreamReader === 'undefined') {
8147 return false;
8148 }
8149
8150 var xhr = new XMLHttpRequest();
8151 xhr.open('GET', 'https://example.com', true);
8152 xhr.responseType = 'ms-stream';
8153 return xhr.responseType === 'ms-stream';
8154 } catch (e) {
8155 _logger2.default.w('MSStreamLoader', e.message);
8156 return false;
8157 }
8158 }
8159 }]);
8160
8161 function MSStreamLoader(seekHandler, config) {
8162 _classCallCheck(this, MSStreamLoader);
8163
8164 var _this = _possibleConstructorReturn(this, (MSStreamLoader.__proto__ || Object.getPrototypeOf(MSStreamLoader)).call(this, 'xhr-msstream-loader'));
8165
8166 _this.TAG = 'MSStreamLoader';
8167
8168 _this._seekHandler = seekHandler;
8169 _this._config = config;
8170 _this._needStash = true;
8171
8172 _this._xhr = null;
8173 _this._reader = null; // MSStreamReader
8174
8175 _this._totalRange = null;
8176 _this._currentRange = null;
8177
8178 _this._currentRequestURL = null;
8179 _this._currentRedirectedURL = null;
8180
8181 _this._contentLength = null;
8182 _this._receivedLength = 0;
8183
8184 _this._bufferLimit = 16 * 1024 * 1024; // 16MB
8185 _this._lastTimeBufferSize = 0;
8186 _this._isReconnecting = false;
8187 return _this;
8188 }
8189
8190 _createClass(MSStreamLoader, [{
8191 key: 'destroy',
8192 value: function destroy() {
8193 if (this.isWorking()) {
8194 this.abort();
8195 }
8196 if (this._reader) {
8197 this._reader.onprogress = null;
8198 this._reader.onload = null;
8199 this._reader.onerror = null;
8200 this._reader = null;
8201 }
8202 if (this._xhr) {
8203 this._xhr.onreadystatechange = null;
8204 this._xhr = null;
8205 }
8206 _get(MSStreamLoader.prototype.__proto__ || Object.getPrototypeOf(MSStreamLoader.prototype), 'destroy', this).call(this);
8207 }
8208 }, {
8209 key: 'open',
8210 value: function open(dataSource, range) {
8211 this._internalOpen(dataSource, range, false);
8212 }
8213 }, {
8214 key: '_internalOpen',
8215 value: function _internalOpen(dataSource, range, isSubrange) {
8216 this._dataSource = dataSource;
8217
8218 if (!isSubrange) {
8219 this._totalRange = range;
8220 } else {
8221 this._currentRange = range;
8222 }
8223
8224 var sourceURL = dataSource.url;
8225 if (this._config.reuseRedirectedURL) {
8226 if (this._currentRedirectedURL != undefined) {
8227 sourceURL = this._currentRedirectedURL;
8228 } else if (dataSource.redirectedURL != undefined) {
8229 sourceURL = dataSource.redirectedURL;
8230 }
8231 }
8232
8233 var seekConfig = this._seekHandler.getConfig(sourceURL, range);
8234 this._currentRequestURL = seekConfig.url;
8235
8236 var reader = this._reader = new self.MSStreamReader();
8237 reader.onprogress = this._msrOnProgress.bind(this);
8238 reader.onload = this._msrOnLoad.bind(this);
8239 reader.onerror = this._msrOnError.bind(this);
8240
8241 var xhr = this._xhr = new XMLHttpRequest();
8242 xhr.open('GET', seekConfig.url, true);
8243 xhr.responseType = 'ms-stream';
8244 xhr.onreadystatechange = this._xhrOnReadyStateChange.bind(this);
8245 xhr.onerror = this._xhrOnError.bind(this);
8246
8247 if (dataSource.withCredentials) {
8248 xhr.withCredentials = true;
8249 }
8250
8251 if (_typeof(seekConfig.headers) === 'object') {
8252 var headers = seekConfig.headers;
8253
8254 for (var key in headers) {
8255 if (headers.hasOwnProperty(key)) {
8256 xhr.setRequestHeader(key, headers[key]);
8257 }
8258 }
8259 }
8260
8261 // add additional headers
8262 if (_typeof(this._config.headers) === 'object') {
8263 var _headers = this._config.headers;
8264
8265 for (var _key in _headers) {
8266 if (_headers.hasOwnProperty(_key)) {
8267 xhr.setRequestHeader(_key, _headers[_key]);
8268 }
8269 }
8270 }
8271
8272 if (this._isReconnecting) {
8273 this._isReconnecting = false;
8274 } else {
8275 this._status = _loader.LoaderStatus.kConnecting;
8276 }
8277 xhr.send();
8278 }
8279 }, {
8280 key: 'abort',
8281 value: function abort() {
8282 this._internalAbort();
8283 this._status = _loader.LoaderStatus.kComplete;
8284 }
8285 }, {
8286 key: '_internalAbort',
8287 value: function _internalAbort() {
8288 if (this._reader) {
8289 if (this._reader.readyState === 1) {
8290 // LOADING
8291 this._reader.abort();
8292 }
8293 this._reader.onprogress = null;
8294 this._reader.onload = null;
8295 this._reader.onerror = null;
8296 this._reader = null;
8297 }
8298 if (this._xhr) {
8299 this._xhr.abort();
8300 this._xhr.onreadystatechange = null;
8301 this._xhr = null;
8302 }
8303 }
8304 }, {
8305 key: '_xhrOnReadyStateChange',
8306 value: function _xhrOnReadyStateChange(e) {
8307 var xhr = e.target;
8308
8309 if (xhr.readyState === 2) {
8310 // HEADERS_RECEIVED
8311 if (xhr.status >= 200 && xhr.status <= 299) {
8312 this._status = _loader.LoaderStatus.kBuffering;
8313
8314 if (xhr.responseURL != undefined) {
8315 var redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
8316 if (xhr.responseURL !== this._currentRequestURL && redirectedURL !== this._currentRedirectedURL) {
8317 this._currentRedirectedURL = redirectedURL;
8318 if (this._onURLRedirect) {
8319 this._onURLRedirect(redirectedURL);
8320 }
8321 }
8322 }
8323
8324 var lengthHeader = xhr.getResponseHeader('Content-Length');
8325 if (lengthHeader != null && this._contentLength == null) {
8326 var length = parseInt(lengthHeader);
8327 if (length > 0) {
8328 this._contentLength = length;
8329 if (this._onContentLengthKnown) {
8330 this._onContentLengthKnown(this._contentLength);
8331 }
8332 }
8333 }
8334 } else {
8335 this._status = _loader.LoaderStatus.kError;
8336 if (this._onError) {
8337 this._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: xhr.status, msg: xhr.statusText });
8338 } else {
8339 throw new _exception.RuntimeException('MSStreamLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
8340 }
8341 }
8342 } else if (xhr.readyState === 3) {
8343 // LOADING
8344 if (xhr.status >= 200 && xhr.status <= 299) {
8345 this._status = _loader.LoaderStatus.kBuffering;
8346
8347 var msstream = xhr.response;
8348 this._reader.readAsArrayBuffer(msstream);
8349 }
8350 }
8351 }
8352 }, {
8353 key: '_xhrOnError',
8354 value: function _xhrOnError(e) {
8355 this._status = _loader.LoaderStatus.kError;
8356 var type = _loader.LoaderErrors.EXCEPTION;
8357 var info = { code: -1, msg: e.constructor.name + ' ' + e.type };
8358
8359 if (this._onError) {
8360 this._onError(type, info);
8361 } else {
8362 throw new _exception.RuntimeException(info.msg);
8363 }
8364 }
8365 }, {
8366 key: '_msrOnProgress',
8367 value: function _msrOnProgress(e) {
8368 var reader = e.target;
8369 var bigbuffer = reader.result;
8370 if (bigbuffer == null) {
8371 // result may be null, workaround for buggy M$
8372 this._doReconnectIfNeeded();
8373 return;
8374 }
8375
8376 var slice = bigbuffer.slice(this._lastTimeBufferSize);
8377 this._lastTimeBufferSize = bigbuffer.byteLength;
8378 var byteStart = this._totalRange.from + this._receivedLength;
8379 this._receivedLength += slice.byteLength;
8380
8381 if (this._onDataArrival) {
8382 this._onDataArrival(slice, byteStart, this._receivedLength);
8383 }
8384
8385 if (bigbuffer.byteLength >= this._bufferLimit) {
8386 _logger2.default.v(this.TAG, 'MSStream buffer exceeded max size near ' + (byteStart + slice.byteLength) + ', reconnecting...');
8387 this._doReconnectIfNeeded();
8388 }
8389 }
8390 }, {
8391 key: '_doReconnectIfNeeded',
8392 value: function _doReconnectIfNeeded() {
8393 if (this._contentLength == null || this._receivedLength < this._contentLength) {
8394 this._isReconnecting = true;
8395 this._lastTimeBufferSize = 0;
8396 this._internalAbort();
8397
8398 var range = {
8399 from: this._totalRange.from + this._receivedLength,
8400 to: -1
8401 };
8402 this._internalOpen(this._dataSource, range, true);
8403 }
8404 }
8405 }, {
8406 key: '_msrOnLoad',
8407 value: function _msrOnLoad(e) {
8408 // actually it is onComplete event
8409 this._status = _loader.LoaderStatus.kComplete;
8410 if (this._onComplete) {
8411 this._onComplete(this._totalRange.from, this._totalRange.from + this._receivedLength - 1);
8412 }
8413 }
8414 }, {
8415 key: '_msrOnError',
8416 value: function _msrOnError(e) {
8417 this._status = _loader.LoaderStatus.kError;
8418 var type = 0;
8419 var info = null;
8420
8421 if (this._contentLength && this._receivedLength < this._contentLength) {
8422 type = _loader.LoaderErrors.EARLY_EOF;
8423 info = { code: -1, msg: 'MSStream meet Early-Eof' };
8424 } else {
8425 type = _loader.LoaderErrors.EARLY_EOF;
8426 info = { code: -1, msg: e.constructor.name + ' ' + e.type };
8427 }
8428
8429 if (this._onError) {
8430 this._onError(type, info);
8431 } else {
8432 throw new _exception.RuntimeException(info.msg);
8433 }
8434 }
8435 }]);
8436
8437 return MSStreamLoader;
8438}(_loader.BaseLoader);
8439
8440exports.default = MSStreamLoader;
8441
8442},{"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24}],31:[function(_dereq_,module,exports){
8443'use strict';
8444
8445Object.defineProperty(exports, "__esModule", {
8446 value: true
8447});
8448
8449var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
8450
8451var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
8452
8453var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8454
8455var _logger = _dereq_('../utils/logger.js');
8456
8457var _logger2 = _interopRequireDefault(_logger);
8458
8459var _speedSampler = _dereq_('./speed-sampler.js');
8460
8461var _speedSampler2 = _interopRequireDefault(_speedSampler);
8462
8463var _loader = _dereq_('./loader.js');
8464
8465var _exception = _dereq_('../utils/exception.js');
8466
8467function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8468
8469function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8470
8471function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
8472
8473function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
8474 * Copyright (C) 2016 Bilibili. All Rights Reserved.
8475 *
8476 * @author zheng qian <xqq@xqq.im>
8477 *
8478 * Licensed under the Apache License, Version 2.0 (the "License");
8479 * you may not use this file except in compliance with the License.
8480 * You may obtain a copy of the License at
8481 *
8482 * http://www.apache.org/licenses/LICENSE-2.0
8483 *
8484 * Unless required by applicable law or agreed to in writing, software
8485 * distributed under the License is distributed on an "AS IS" BASIS,
8486 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8487 * See the License for the specific language governing permissions and
8488 * limitations under the License.
8489 */
8490
8491// Universal IO Loader, implemented by adding Range header in xhr's request header
8492var RangeLoader = function (_BaseLoader) {
8493 _inherits(RangeLoader, _BaseLoader);
8494
8495 _createClass(RangeLoader, null, [{
8496 key: 'isSupported',
8497 value: function isSupported() {
8498 try {
8499 var xhr = new XMLHttpRequest();
8500 xhr.open('GET', 'https://example.com', true);
8501 xhr.responseType = 'arraybuffer';
8502 return xhr.responseType === 'arraybuffer';
8503 } catch (e) {
8504 _logger2.default.w('RangeLoader', e.message);
8505 return false;
8506 }
8507 }
8508 }]);
8509
8510 function RangeLoader(seekHandler, config) {
8511 _classCallCheck(this, RangeLoader);
8512
8513 var _this = _possibleConstructorReturn(this, (RangeLoader.__proto__ || Object.getPrototypeOf(RangeLoader)).call(this, 'xhr-range-loader'));
8514
8515 _this.TAG = 'RangeLoader';
8516
8517 _this._seekHandler = seekHandler;
8518 _this._config = config;
8519 _this._needStash = false;
8520
8521 _this._chunkSizeKBList = [128, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 5120, 6144, 7168, 8192];
8522 _this._currentChunkSizeKB = 384;
8523 _this._currentSpeedNormalized = 0;
8524 _this._zeroSpeedChunkCount = 0;
8525
8526 _this._xhr = null;
8527 _this._speedSampler = new _speedSampler2.default();
8528
8529 _this._requestAbort = false;
8530 _this._waitForTotalLength = false;
8531 _this._totalLengthReceived = false;
8532
8533 _this._currentRequestURL = null;
8534 _this._currentRedirectedURL = null;
8535 _this._currentRequestRange = null;
8536 _this._totalLength = null; // size of the entire file
8537 _this._contentLength = null; // Content-Length of entire request range
8538 _this._receivedLength = 0; // total received bytes
8539 _this._lastTimeLoaded = 0; // received bytes of current request sub-range
8540 return _this;
8541 }
8542
8543 _createClass(RangeLoader, [{
8544 key: 'destroy',
8545 value: function destroy() {
8546 if (this.isWorking()) {
8547 this.abort();
8548 }
8549 if (this._xhr) {
8550 this._xhr.onreadystatechange = null;
8551 this._xhr.onprogress = null;
8552 this._xhr.onload = null;
8553 this._xhr.onerror = null;
8554 this._xhr = null;
8555 }
8556 _get(RangeLoader.prototype.__proto__ || Object.getPrototypeOf(RangeLoader.prototype), 'destroy', this).call(this);
8557 }
8558 }, {
8559 key: 'open',
8560 value: function open(dataSource, range) {
8561 this._dataSource = dataSource;
8562 this._range = range;
8563 this._status = _loader.LoaderStatus.kConnecting;
8564
8565 var useRefTotalLength = false;
8566 if (this._dataSource.filesize != undefined && this._dataSource.filesize !== 0) {
8567 useRefTotalLength = true;
8568 this._totalLength = this._dataSource.filesize;
8569 }
8570
8571 if (!this._totalLengthReceived && !useRefTotalLength) {
8572 // We need total filesize
8573 this._waitForTotalLength = true;
8574 this._internalOpen(this._dataSource, { from: 0, to: -1 });
8575 } else {
8576 // We have filesize, start loading
8577 this._openSubRange();
8578 }
8579 }
8580 }, {
8581 key: '_openSubRange',
8582 value: function _openSubRange() {
8583 var chunkSize = this._currentChunkSizeKB * 1024;
8584
8585 var from = this._range.from + this._receivedLength;
8586 var to = from + chunkSize;
8587
8588 if (this._contentLength != null) {
8589 if (to - this._range.from >= this._contentLength) {
8590 to = this._range.from + this._contentLength - 1;
8591 }
8592 }
8593
8594 this._currentRequestRange = { from: from, to: to };
8595 this._internalOpen(this._dataSource, this._currentRequestRange);
8596 }
8597 }, {
8598 key: '_internalOpen',
8599 value: function _internalOpen(dataSource, range) {
8600 this._lastTimeLoaded = 0;
8601
8602 var sourceURL = dataSource.url;
8603 if (this._config.reuseRedirectedURL) {
8604 if (this._currentRedirectedURL != undefined) {
8605 sourceURL = this._currentRedirectedURL;
8606 } else if (dataSource.redirectedURL != undefined) {
8607 sourceURL = dataSource.redirectedURL;
8608 }
8609 }
8610
8611 var seekConfig = this._seekHandler.getConfig(sourceURL, range);
8612 this._currentRequestURL = seekConfig.url;
8613
8614 var xhr = this._xhr = new XMLHttpRequest();
8615 xhr.open('GET', seekConfig.url, true);
8616 xhr.responseType = 'arraybuffer';
8617 xhr.onreadystatechange = this._onReadyStateChange.bind(this);
8618 xhr.onprogress = this._onProgress.bind(this);
8619 xhr.onload = this._onLoad.bind(this);
8620 xhr.onerror = this._onXhrError.bind(this);
8621
8622 if (dataSource.withCredentials) {
8623 xhr.withCredentials = true;
8624 }
8625
8626 if (_typeof(seekConfig.headers) === 'object') {
8627 var headers = seekConfig.headers;
8628
8629 for (var key in headers) {
8630 if (headers.hasOwnProperty(key)) {
8631 xhr.setRequestHeader(key, headers[key]);
8632 }
8633 }
8634 }
8635
8636 // add additional headers
8637 if (_typeof(this._config.headers) === 'object') {
8638 var _headers = this._config.headers;
8639
8640 for (var _key in _headers) {
8641 if (_headers.hasOwnProperty(_key)) {
8642 xhr.setRequestHeader(_key, _headers[_key]);
8643 }
8644 }
8645 }
8646
8647 xhr.send();
8648 }
8649 }, {
8650 key: 'abort',
8651 value: function abort() {
8652 this._requestAbort = true;
8653 this._internalAbort();
8654 this._status = _loader.LoaderStatus.kComplete;
8655 }
8656 }, {
8657 key: '_internalAbort',
8658 value: function _internalAbort() {
8659 if (this._xhr) {
8660 this._xhr.onreadystatechange = null;
8661 this._xhr.onprogress = null;
8662 this._xhr.onload = null;
8663 this._xhr.onerror = null;
8664 this._xhr.abort();
8665 this._xhr = null;
8666 }
8667 }
8668 }, {
8669 key: '_onReadyStateChange',
8670 value: function _onReadyStateChange(e) {
8671 var xhr = e.target;
8672
8673 if (xhr.readyState === 2) {
8674 // HEADERS_RECEIVED
8675 if (xhr.responseURL != undefined) {
8676 // if the browser support this property
8677 var redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
8678 if (xhr.responseURL !== this._currentRequestURL && redirectedURL !== this._currentRedirectedURL) {
8679 this._currentRedirectedURL = redirectedURL;
8680 if (this._onURLRedirect) {
8681 this._onURLRedirect(redirectedURL);
8682 }
8683 }
8684 }
8685
8686 if (xhr.status >= 200 && xhr.status <= 299) {
8687 if (this._waitForTotalLength) {
8688 return;
8689 }
8690 this._status = _loader.LoaderStatus.kBuffering;
8691 } else {
8692 this._status = _loader.LoaderStatus.kError;
8693 if (this._onError) {
8694 this._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: xhr.status, msg: xhr.statusText });
8695 } else {
8696 throw new _exception.RuntimeException('RangeLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
8697 }
8698 }
8699 }
8700 }
8701 }, {
8702 key: '_onProgress',
8703 value: function _onProgress(e) {
8704 if (this._status === _loader.LoaderStatus.kError) {
8705 // Ignore error response
8706 return;
8707 }
8708
8709 if (this._contentLength === null) {
8710 var openNextRange = false;
8711
8712 if (this._waitForTotalLength) {
8713 this._waitForTotalLength = false;
8714 this._totalLengthReceived = true;
8715 openNextRange = true;
8716
8717 var total = e.total;
8718 this._internalAbort();
8719 if (total != null & total !== 0) {
8720 this._totalLength = total;
8721 }
8722 }
8723
8724 // calculate currrent request range's contentLength
8725 if (this._range.to === -1) {
8726 this._contentLength = this._totalLength - this._range.from;
8727 } else {
8728 // to !== -1
8729 this._contentLength = this._range.to - this._range.from + 1;
8730 }
8731
8732 if (openNextRange) {
8733 this._openSubRange();
8734 return;
8735 }
8736 if (this._onContentLengthKnown) {
8737 this._onContentLengthKnown(this._contentLength);
8738 }
8739 }
8740
8741 var delta = e.loaded - this._lastTimeLoaded;
8742 this._lastTimeLoaded = e.loaded;
8743 this._speedSampler.addBytes(delta);
8744 }
8745 }, {
8746 key: '_normalizeSpeed',
8747 value: function _normalizeSpeed(input) {
8748 var list = this._chunkSizeKBList;
8749 var last = list.length - 1;
8750 var mid = 0;
8751 var lbound = 0;
8752 var ubound = last;
8753
8754 if (input < list[0]) {
8755 return list[0];
8756 }
8757
8758 while (lbound <= ubound) {
8759 mid = lbound + Math.floor((ubound - lbound) / 2);
8760 if (mid === last || input >= list[mid] && input < list[mid + 1]) {
8761 return list[mid];
8762 } else if (list[mid] < input) {
8763 lbound = mid + 1;
8764 } else {
8765 ubound = mid - 1;
8766 }
8767 }
8768 }
8769 }, {
8770 key: '_onLoad',
8771 value: function _onLoad(e) {
8772 if (this._status === _loader.LoaderStatus.kError) {
8773 // Ignore error response
8774 return;
8775 }
8776
8777 if (this._waitForTotalLength) {
8778 this._waitForTotalLength = false;
8779 return;
8780 }
8781
8782 this._lastTimeLoaded = 0;
8783 var KBps = this._speedSampler.lastSecondKBps;
8784 if (KBps === 0) {
8785 this._zeroSpeedChunkCount++;
8786 if (this._zeroSpeedChunkCount >= 3) {
8787 // Try get currentKBps after 3 chunks
8788 KBps = this._speedSampler.currentKBps;
8789 }
8790 }
8791
8792 if (KBps !== 0) {
8793 var normalized = this._normalizeSpeed(KBps);
8794 if (this._currentSpeedNormalized !== normalized) {
8795 this._currentSpeedNormalized = normalized;
8796 this._currentChunkSizeKB = normalized;
8797 }
8798 }
8799
8800 var chunk = e.target.response;
8801 var byteStart = this._range.from + this._receivedLength;
8802 this._receivedLength += chunk.byteLength;
8803
8804 var reportComplete = false;
8805
8806 if (this._contentLength != null && this._receivedLength < this._contentLength) {
8807 // continue load next chunk
8808 this._openSubRange();
8809 } else {
8810 reportComplete = true;
8811 }
8812
8813 // dispatch received chunk
8814 if (this._onDataArrival) {
8815 this._onDataArrival(chunk, byteStart, this._receivedLength);
8816 }
8817
8818 if (reportComplete) {
8819 this._status = _loader.LoaderStatus.kComplete;
8820 if (this._onComplete) {
8821 this._onComplete(this._range.from, this._range.from + this._receivedLength - 1);
8822 }
8823 }
8824 }
8825 }, {
8826 key: '_onXhrError',
8827 value: function _onXhrError(e) {
8828 this._status = _loader.LoaderStatus.kError;
8829 var type = 0;
8830 var info = null;
8831
8832 if (this._contentLength && this._receivedLength > 0 && this._receivedLength < this._contentLength) {
8833 type = _loader.LoaderErrors.EARLY_EOF;
8834 info = { code: -1, msg: 'RangeLoader meet Early-Eof' };
8835 } else {
8836 type = _loader.LoaderErrors.EXCEPTION;
8837 info = { code: -1, msg: e.constructor.name + ' ' + e.type };
8838 }
8839
8840 if (this._onError) {
8841 this._onError(type, info);
8842 } else {
8843 throw new _exception.RuntimeException(info.msg);
8844 }
8845 }
8846 }, {
8847 key: 'currentSpeed',
8848 get: function get() {
8849 return this._speedSampler.lastSecondKBps;
8850 }
8851 }]);
8852
8853 return RangeLoader;
8854}(_loader.BaseLoader);
8855
8856exports.default = RangeLoader;
8857
8858},{"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24,"./speed-sampler.js":27}],32:[function(_dereq_,module,exports){
8859'use strict';
8860
8861Object.defineProperty(exports, "__esModule", {
8862 value: true
8863});
8864
8865var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
8866
8867var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
8868 * Copyright (C) 2016 Bilibili. All Rights Reserved.
8869 *
8870 * @author zheng qian <xqq@xqq.im>
8871 *
8872 * Licensed under the Apache License, Version 2.0 (the "License");
8873 * you may not use this file except in compliance with the License.
8874 * You may obtain a copy of the License at
8875 *
8876 * http://www.apache.org/licenses/LICENSE-2.0
8877 *
8878 * Unless required by applicable law or agreed to in writing, software
8879 * distributed under the License is distributed on an "AS IS" BASIS,
8880 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8881 * See the License for the specific language governing permissions and
8882 * limitations under the License.
8883 */
8884
8885var _events = _dereq_('events');
8886
8887var _events2 = _interopRequireDefault(_events);
8888
8889var _logger = _dereq_('../utils/logger.js');
8890
8891var _logger2 = _interopRequireDefault(_logger);
8892
8893var _browser = _dereq_('../utils/browser.js');
8894
8895var _browser2 = _interopRequireDefault(_browser);
8896
8897var _playerEvents = _dereq_('./player-events.js');
8898
8899var _playerEvents2 = _interopRequireDefault(_playerEvents);
8900
8901var _transmuxer = _dereq_('../core/transmuxer.js');
8902
8903var _transmuxer2 = _interopRequireDefault(_transmuxer);
8904
8905var _transmuxingEvents = _dereq_('../core/transmuxing-events.js');
8906
8907var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
8908
8909var _mseController = _dereq_('../core/mse-controller.js');
8910
8911var _mseController2 = _interopRequireDefault(_mseController);
8912
8913var _mseEvents = _dereq_('../core/mse-events.js');
8914
8915var _mseEvents2 = _interopRequireDefault(_mseEvents);
8916
8917var _playerErrors = _dereq_('./player-errors.js');
8918
8919var _config = _dereq_('../config.js');
8920
8921var _exception = _dereq_('../utils/exception.js');
8922
8923function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8924
8925function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8926
8927var FlvPlayer = function () {
8928 function FlvPlayer(mediaDataSource, config) {
8929 _classCallCheck(this, FlvPlayer);
8930
8931 this.TAG = 'FlvPlayer';
8932 this._type = 'FlvPlayer';
8933 this._emitter = new _events2.default();
8934
8935 this._config = (0, _config.createDefaultConfig)();
8936 if ((typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object') {
8937 Object.assign(this._config, config);
8938 }
8939
8940 if (mediaDataSource.type.toLowerCase() !== 'flv') {
8941 throw new _exception.InvalidArgumentException('FlvPlayer requires an flv MediaDataSource input!');
8942 }
8943
8944 if (mediaDataSource.isLive === true) {
8945 this._config.isLive = true;
8946 }
8947
8948 this.e = {
8949 onvLoadedMetadata: this._onvLoadedMetadata.bind(this),
8950 onvSeeking: this._onvSeeking.bind(this),
8951 onvCanPlay: this._onvCanPlay.bind(this),
8952 onvStalled: this._onvStalled.bind(this),
8953 onvProgress: this._onvProgress.bind(this)
8954 };
8955
8956 if (self.performance && self.performance.now) {
8957 this._now = self.performance.now.bind(self.performance);
8958 } else {
8959 this._now = Date.now;
8960 }
8961
8962 this._pendingSeekTime = null; // in seconds
8963 this._requestSetTime = false;
8964 this._seekpointRecord = null;
8965 this._progressChecker = null;
8966
8967 this._mediaDataSource = mediaDataSource;
8968 this._mediaElement = null;
8969 this._msectl = null;
8970 this._transmuxer = null;
8971
8972 this._mseSourceOpened = false;
8973 this._hasPendingLoad = false;
8974 this._receivedCanPlay = false;
8975
8976 this._mediaInfo = null;
8977 this._statisticsInfo = null;
8978
8979 var chromeNeedIDRFix = _browser2.default.chrome && (_browser2.default.version.major < 50 || _browser2.default.version.major === 50 && _browser2.default.version.build < 2661);
8980 this._alwaysSeekKeyframe = chromeNeedIDRFix || _browser2.default.msedge || _browser2.default.msie ? true : false;
8981
8982 if (this._alwaysSeekKeyframe) {
8983 this._config.accurateSeek = false;
8984 }
8985 }
8986
8987 _createClass(FlvPlayer, [{
8988 key: 'destroy',
8989 value: function destroy() {
8990 if (this._progressChecker != null) {
8991 window.clearInterval(this._progressChecker);
8992 this._progressChecker = null;
8993 }
8994 if (this._transmuxer) {
8995 this.unload();
8996 }
8997 if (this._mediaElement) {
8998 this.detachMediaElement();
8999 }
9000 this.e = null;
9001 this._mediaDataSource = null;
9002
9003 this._emitter.removeAllListeners();
9004 this._emitter = null;
9005 }
9006 }, {
9007 key: 'on',
9008 value: function on(event, listener) {
9009 var _this = this;
9010
9011 if (event === _playerEvents2.default.MEDIA_INFO) {
9012 if (this._mediaInfo != null) {
9013 Promise.resolve().then(function () {
9014 _this._emitter.emit(_playerEvents2.default.MEDIA_INFO, _this.mediaInfo);
9015 });
9016 }
9017 } else if (event === _playerEvents2.default.STATISTICS_INFO) {
9018 if (this._statisticsInfo != null) {
9019 Promise.resolve().then(function () {
9020 _this._emitter.emit(_playerEvents2.default.STATISTICS_INFO, _this.statisticsInfo);
9021 });
9022 }
9023 }
9024 this._emitter.addListener(event, listener);
9025 }
9026 }, {
9027 key: 'off',
9028 value: function off(event, listener) {
9029 this._emitter.removeListener(event, listener);
9030 }
9031 }, {
9032 key: 'attachMediaElement',
9033 value: function attachMediaElement(mediaElement) {
9034 var _this2 = this;
9035
9036 this._mediaElement = mediaElement;
9037 mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata);
9038 mediaElement.addEventListener('seeking', this.e.onvSeeking);
9039 mediaElement.addEventListener('canplay', this.e.onvCanPlay);
9040 mediaElement.addEventListener('stalled', this.e.onvStalled);
9041 mediaElement.addEventListener('progress', this.e.onvProgress);
9042
9043 this._msectl = new _mseController2.default(this._config);
9044
9045 this._msectl.on(_mseEvents2.default.UPDATE_END, this._onmseUpdateEnd.bind(this));
9046 this._msectl.on(_mseEvents2.default.BUFFER_FULL, this._onmseBufferFull.bind(this));
9047 this._msectl.on(_mseEvents2.default.SOURCE_OPEN, function () {
9048 _this2._mseSourceOpened = true;
9049 if (_this2._hasPendingLoad) {
9050 _this2._hasPendingLoad = false;
9051 _this2.load();
9052 }
9053 });
9054 this._msectl.on(_mseEvents2.default.ERROR, function (info) {
9055 _this2._emitter.emit(_playerEvents2.default.ERROR, _playerErrors.ErrorTypes.MEDIA_ERROR, _playerErrors.ErrorDetails.MEDIA_MSE_ERROR, info);
9056 });
9057
9058 this._msectl.attachMediaElement(mediaElement);
9059
9060 if (this._pendingSeekTime != null) {
9061 try {
9062 mediaElement.currentTime = this._pendingSeekTime;
9063 this._pendingSeekTime = null;
9064 } catch (e) {
9065 // IE11 may throw InvalidStateError if readyState === 0
9066 // We can defer set currentTime operation after loadedmetadata
9067 }
9068 }
9069 }
9070 }, {
9071 key: 'detachMediaElement',
9072 value: function detachMediaElement() {
9073 if (this._mediaElement) {
9074 this._msectl.detachMediaElement();
9075 this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
9076 this._mediaElement.removeEventListener('seeking', this.e.onvSeeking);
9077 this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay);
9078 this._mediaElement.removeEventListener('stalled', this.e.onvStalled);
9079 this._mediaElement.removeEventListener('progress', this.e.onvProgress);
9080 this._mediaElement = null;
9081 }
9082 if (this._msectl) {
9083 this._msectl.destroy();
9084 this._msectl = null;
9085 }
9086 }
9087 }, {
9088 key: 'load',
9089 value: function load() {
9090 var _this3 = this;
9091
9092 if (!this._mediaElement) {
9093 throw new _exception.IllegalStateException('HTMLMediaElement must be attached before load()!');
9094 }
9095 if (this._transmuxer) {
9096 throw new _exception.IllegalStateException('FlvPlayer.load() has been called, please call unload() first!');
9097 }
9098 if (this._hasPendingLoad) {
9099 return;
9100 }
9101
9102 if (this._config.deferLoadAfterSourceOpen && this._mseSourceOpened === false) {
9103 this._hasPendingLoad = true;
9104 return;
9105 }
9106
9107 if (this._mediaElement.readyState > 0) {
9108 this._requestSetTime = true;
9109 // IE11 may throw InvalidStateError if readyState === 0
9110 this._mediaElement.currentTime = 0;
9111 }
9112
9113 this._transmuxer = new _transmuxer2.default(this._mediaDataSource, this._config);
9114
9115 this._transmuxer.on(_transmuxingEvents2.default.INIT_SEGMENT, function (type, is) {
9116 _this3._msectl.appendInitSegment(is);
9117 });
9118 this._transmuxer.on(_transmuxingEvents2.default.MEDIA_SEGMENT, function (type, ms) {
9119 _this3._msectl.appendMediaSegment(ms);
9120
9121 // lazyLoad check
9122 if (_this3._config.lazyLoad && !_this3._config.isLive) {
9123 var currentTime = _this3._mediaElement.currentTime;
9124 if (ms.info.endDts >= (currentTime + _this3._config.lazyLoadMaxDuration) * 1000) {
9125 if (_this3._progressChecker == null) {
9126 _logger2.default.v(_this3.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
9127 _this3._suspendTransmuxer();
9128 }
9129 }
9130 }
9131 });
9132 this._transmuxer.on(_transmuxingEvents2.default.LOADING_COMPLETE, function () {
9133 _this3._msectl.endOfStream();
9134 _this3._emitter.emit(_playerEvents2.default.LOADING_COMPLETE);
9135 });
9136 this._transmuxer.on(_transmuxingEvents2.default.RECOVERED_EARLY_EOF, function () {
9137 _this3._emitter.emit(_playerEvents2.default.RECOVERED_EARLY_EOF);
9138 });
9139 this._transmuxer.on(_transmuxingEvents2.default.IO_ERROR, function (detail, info) {
9140 _this3._emitter.emit(_playerEvents2.default.ERROR, _playerErrors.ErrorTypes.NETWORK_ERROR, detail, info);
9141 });
9142 this._transmuxer.on(_transmuxingEvents2.default.DEMUX_ERROR, function (detail, info) {
9143 _this3._emitter.emit(_playerEvents2.default.ERROR, _playerErrors.ErrorTypes.MEDIA_ERROR, detail, { code: -1, msg: info });
9144 });
9145 this._transmuxer.on(_transmuxingEvents2.default.MEDIA_INFO, function (mediaInfo) {
9146 _this3._mediaInfo = mediaInfo;
9147 _this3._emitter.emit(_playerEvents2.default.MEDIA_INFO, Object.assign({}, mediaInfo));
9148 });
9149 this._transmuxer.on(_transmuxingEvents2.default.METADATA_ARRIVED, function (metadata) {
9150 _this3._emitter.emit(_playerEvents2.default.METADATA_ARRIVED, metadata);
9151 });
9152 this._transmuxer.on(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, function (data) {
9153 _this3._emitter.emit(_playerEvents2.default.SCRIPTDATA_ARRIVED, data);
9154 });
9155 this._transmuxer.on(_transmuxingEvents2.default.STATISTICS_INFO, function (statInfo) {
9156 _this3._statisticsInfo = _this3._fillStatisticsInfo(statInfo);
9157 _this3._emitter.emit(_playerEvents2.default.STATISTICS_INFO, Object.assign({}, _this3._statisticsInfo));
9158 });
9159 this._transmuxer.on(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, function (milliseconds) {
9160 if (_this3._mediaElement && !_this3._config.accurateSeek) {
9161 _this3._requestSetTime = true;
9162 _this3._mediaElement.currentTime = milliseconds / 1000;
9163 }
9164 });
9165
9166 this._transmuxer.open();
9167 }
9168 }, {
9169 key: 'unload',
9170 value: function unload() {
9171 if (this._mediaElement) {
9172 this._mediaElement.pause();
9173 }
9174 if (this._msectl) {
9175 this._msectl.seek(0);
9176 }
9177 if (this._transmuxer) {
9178 this._transmuxer.close();
9179 this._transmuxer.destroy();
9180 this._transmuxer = null;
9181 }
9182 }
9183 }, {
9184 key: 'play',
9185 value: function play() {
9186 return this._mediaElement.play();
9187 }
9188 }, {
9189 key: 'pause',
9190 value: function pause() {
9191 this._mediaElement.pause();
9192 }
9193 }, {
9194 key: '_fillStatisticsInfo',
9195 value: function _fillStatisticsInfo(statInfo) {
9196 statInfo.playerType = this._type;
9197
9198 if (!(this._mediaElement instanceof HTMLVideoElement)) {
9199 return statInfo;
9200 }
9201
9202 var hasQualityInfo = true;
9203 var decoded = 0;
9204 var dropped = 0;
9205
9206 if (this._mediaElement.getVideoPlaybackQuality) {
9207 var quality = this._mediaElement.getVideoPlaybackQuality();
9208 decoded = quality.totalVideoFrames;
9209 dropped = quality.droppedVideoFrames;
9210 } else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
9211 decoded = this._mediaElement.webkitDecodedFrameCount;
9212 dropped = this._mediaElement.webkitDroppedFrameCount;
9213 } else {
9214 hasQualityInfo = false;
9215 }
9216
9217 if (hasQualityInfo) {
9218 statInfo.decodedFrames = decoded;
9219 statInfo.droppedFrames = dropped;
9220 }
9221
9222 return statInfo;
9223 }
9224 }, {
9225 key: '_onmseUpdateEnd',
9226 value: function _onmseUpdateEnd() {
9227 if (!this._config.lazyLoad || this._config.isLive) {
9228 return;
9229 }
9230
9231 var buffered = this._mediaElement.buffered;
9232 var currentTime = this._mediaElement.currentTime;
9233 var currentRangeStart = 0;
9234 var currentRangeEnd = 0;
9235
9236 for (var i = 0; i < buffered.length; i++) {
9237 var start = buffered.start(i);
9238 var end = buffered.end(i);
9239 if (start <= currentTime && currentTime < end) {
9240 currentRangeStart = start;
9241 currentRangeEnd = end;
9242 break;
9243 }
9244 }
9245
9246 if (currentRangeEnd >= currentTime + this._config.lazyLoadMaxDuration && this._progressChecker == null) {
9247 _logger2.default.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
9248 this._suspendTransmuxer();
9249 }
9250 }
9251 }, {
9252 key: '_onmseBufferFull',
9253 value: function _onmseBufferFull() {
9254 _logger2.default.v(this.TAG, 'MSE SourceBuffer is full, suspend transmuxing task');
9255 if (this._progressChecker == null) {
9256 this._suspendTransmuxer();
9257 }
9258 }
9259 }, {
9260 key: '_suspendTransmuxer',
9261 value: function _suspendTransmuxer() {
9262 if (this._transmuxer) {
9263 this._transmuxer.pause();
9264
9265 if (this._progressChecker == null) {
9266 this._progressChecker = window.setInterval(this._checkProgressAndResume.bind(this), 1000);
9267 }
9268 }
9269 }
9270 }, {
9271 key: '_checkProgressAndResume',
9272 value: function _checkProgressAndResume() {
9273 var currentTime = this._mediaElement.currentTime;
9274 var buffered = this._mediaElement.buffered;
9275
9276 var needResume = false;
9277
9278 for (var i = 0; i < buffered.length; i++) {
9279 var from = buffered.start(i);
9280 var to = buffered.end(i);
9281 if (currentTime >= from && currentTime < to) {
9282 if (currentTime >= to - this._config.lazyLoadRecoverDuration) {
9283 needResume = true;
9284 }
9285 break;
9286 }
9287 }
9288
9289 if (needResume) {
9290 window.clearInterval(this._progressChecker);
9291 this._progressChecker = null;
9292 if (needResume) {
9293 _logger2.default.v(this.TAG, 'Continue loading from paused position');
9294 this._transmuxer.resume();
9295 }
9296 }
9297 }
9298 }, {
9299 key: '_isTimepointBuffered',
9300 value: function _isTimepointBuffered(seconds) {
9301 var buffered = this._mediaElement.buffered;
9302
9303 for (var i = 0; i < buffered.length; i++) {
9304 var from = buffered.start(i);
9305 var to = buffered.end(i);
9306 if (seconds >= from && seconds < to) {
9307 return true;
9308 }
9309 }
9310 return false;
9311 }
9312 }, {
9313 key: '_internalSeek',
9314 value: function _internalSeek(seconds) {
9315 var directSeek = this._isTimepointBuffered(seconds);
9316
9317 var directSeekBegin = false;
9318 var directSeekBeginTime = 0;
9319
9320 if (seconds < 1.0 && this._mediaElement.buffered.length > 0) {
9321 var videoBeginTime = this._mediaElement.buffered.start(0);
9322 if (videoBeginTime < 1.0 && seconds < videoBeginTime || _browser2.default.safari) {
9323 directSeekBegin = true;
9324 // also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
9325 directSeekBeginTime = _browser2.default.safari ? 0.1 : videoBeginTime;
9326 }
9327 }
9328
9329 if (directSeekBegin) {
9330 // seek to video begin, set currentTime directly if beginPTS buffered
9331 this._requestSetTime = true;
9332 this._mediaElement.currentTime = directSeekBeginTime;
9333 } else if (directSeek) {
9334 // buffered position
9335 if (!this._alwaysSeekKeyframe) {
9336 this._requestSetTime = true;
9337 this._mediaElement.currentTime = seconds;
9338 } else {
9339 var idr = this._msectl.getNearestKeyframe(Math.floor(seconds * 1000));
9340 this._requestSetTime = true;
9341 if (idr != null) {
9342 this._mediaElement.currentTime = idr.dts / 1000;
9343 } else {
9344 this._mediaElement.currentTime = seconds;
9345 }
9346 }
9347 if (this._progressChecker != null) {
9348 this._checkProgressAndResume();
9349 }
9350 } else {
9351 if (this._progressChecker != null) {
9352 window.clearInterval(this._progressChecker);
9353 this._progressChecker = null;
9354 }
9355 this._msectl.seek(seconds);
9356 this._transmuxer.seek(Math.floor(seconds * 1000)); // in milliseconds
9357 // no need to set mediaElement.currentTime if non-accurateSeek,
9358 // just wait for the recommend_seekpoint callback
9359 if (this._config.accurateSeek) {
9360 this._requestSetTime = true;
9361 this._mediaElement.currentTime = seconds;
9362 }
9363 }
9364 }
9365 }, {
9366 key: '_checkAndApplyUnbufferedSeekpoint',
9367 value: function _checkAndApplyUnbufferedSeekpoint() {
9368 if (this._seekpointRecord) {
9369 if (this._seekpointRecord.recordTime <= this._now() - 100) {
9370 var target = this._mediaElement.currentTime;
9371 this._seekpointRecord = null;
9372 if (!this._isTimepointBuffered(target)) {
9373 if (this._progressChecker != null) {
9374 window.clearTimeout(this._progressChecker);
9375 this._progressChecker = null;
9376 }
9377 // .currentTime is consists with .buffered timestamp
9378 // Chrome/Edge use DTS, while FireFox/Safari use PTS
9379 this._msectl.seek(target);
9380 this._transmuxer.seek(Math.floor(target * 1000));
9381 // set currentTime if accurateSeek, or wait for recommend_seekpoint callback
9382 if (this._config.accurateSeek) {
9383 this._requestSetTime = true;
9384 this._mediaElement.currentTime = target;
9385 }
9386 }
9387 } else {
9388 window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50);
9389 }
9390 }
9391 }
9392 }, {
9393 key: '_checkAndResumeStuckPlayback',
9394 value: function _checkAndResumeStuckPlayback(stalled) {
9395 var media = this._mediaElement;
9396 if (stalled || !this._receivedCanPlay || media.readyState < 2) {
9397 // HAVE_CURRENT_DATA
9398 var buffered = media.buffered;
9399 if (buffered.length > 0 && media.currentTime < buffered.start(0)) {
9400 _logger2.default.w(this.TAG, 'Playback seems stuck at ' + media.currentTime + ', seek to ' + buffered.start(0));
9401 this._requestSetTime = true;
9402 this._mediaElement.currentTime = buffered.start(0);
9403 this._mediaElement.removeEventListener('progress', this.e.onvProgress);
9404 }
9405 } else {
9406 // Playback didn't stuck, remove progress event listener
9407 this._mediaElement.removeEventListener('progress', this.e.onvProgress);
9408 }
9409 }
9410 }, {
9411 key: '_onvLoadedMetadata',
9412 value: function _onvLoadedMetadata(e) {
9413 if (this._pendingSeekTime != null) {
9414 this._mediaElement.currentTime = this._pendingSeekTime;
9415 this._pendingSeekTime = null;
9416 }
9417 }
9418 }, {
9419 key: '_onvSeeking',
9420 value: function _onvSeeking(e) {
9421 // handle seeking request from browser's progress bar
9422 var target = this._mediaElement.currentTime;
9423 var buffered = this._mediaElement.buffered;
9424
9425 if (this._requestSetTime) {
9426 this._requestSetTime = false;
9427 return;
9428 }
9429
9430 if (target < 1.0 && buffered.length > 0) {
9431 // seek to video begin, set currentTime directly if beginPTS buffered
9432 var videoBeginTime = buffered.start(0);
9433 if (videoBeginTime < 1.0 && target < videoBeginTime || _browser2.default.safari) {
9434 this._requestSetTime = true;
9435 // also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
9436 this._mediaElement.currentTime = _browser2.default.safari ? 0.1 : videoBeginTime;
9437 return;
9438 }
9439 }
9440
9441 if (this._isTimepointBuffered(target)) {
9442 if (this._alwaysSeekKeyframe) {
9443 var idr = this._msectl.getNearestKeyframe(Math.floor(target * 1000));
9444 if (idr != null) {
9445 this._requestSetTime = true;
9446 this._mediaElement.currentTime = idr.dts / 1000;
9447 }
9448 }
9449 if (this._progressChecker != null) {
9450 this._checkProgressAndResume();
9451 }
9452 return;
9453 }
9454
9455 this._seekpointRecord = {
9456 seekPoint: target,
9457 recordTime: this._now()
9458 };
9459 window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50);
9460 }
9461 }, {
9462 key: '_onvCanPlay',
9463 value: function _onvCanPlay(e) {
9464 this._receivedCanPlay = true;
9465 this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay);
9466 }
9467 }, {
9468 key: '_onvStalled',
9469 value: function _onvStalled(e) {
9470 this._checkAndResumeStuckPlayback(true);
9471 }
9472 }, {
9473 key: '_onvProgress',
9474 value: function _onvProgress(e) {
9475 this._checkAndResumeStuckPlayback();
9476 }
9477 }, {
9478 key: 'type',
9479 get: function get() {
9480 return this._type;
9481 }
9482 }, {
9483 key: 'buffered',
9484 get: function get() {
9485 return this._mediaElement.buffered;
9486 }
9487 }, {
9488 key: 'duration',
9489 get: function get() {
9490 return this._mediaElement.duration;
9491 }
9492 }, {
9493 key: 'volume',
9494 get: function get() {
9495 return this._mediaElement.volume;
9496 },
9497 set: function set(value) {
9498 this._mediaElement.volume = value;
9499 }
9500 }, {
9501 key: 'muted',
9502 get: function get() {
9503 return this._mediaElement.muted;
9504 },
9505 set: function set(muted) {
9506 this._mediaElement.muted = muted;
9507 }
9508 }, {
9509 key: 'currentTime',
9510 get: function get() {
9511 if (this._mediaElement) {
9512 return this._mediaElement.currentTime;
9513 }
9514 return 0;
9515 },
9516 set: function set(seconds) {
9517 if (this._mediaElement) {
9518 this._internalSeek(seconds);
9519 } else {
9520 this._pendingSeekTime = seconds;
9521 }
9522 }
9523 }, {
9524 key: 'mediaInfo',
9525 get: function get() {
9526 return Object.assign({}, this._mediaInfo);
9527 }
9528 }, {
9529 key: 'statisticsInfo',
9530 get: function get() {
9531 if (this._statisticsInfo == null) {
9532 this._statisticsInfo = {};
9533 }
9534 this._statisticsInfo = this._fillStatisticsInfo(this._statisticsInfo);
9535 return Object.assign({}, this._statisticsInfo);
9536 }
9537 }]);
9538
9539 return FlvPlayer;
9540}();
9541
9542exports.default = FlvPlayer;
9543
9544},{"../config.js":5,"../core/mse-controller.js":9,"../core/mse-events.js":10,"../core/transmuxer.js":11,"../core/transmuxing-events.js":13,"../utils/browser.js":39,"../utils/exception.js":40,"../utils/logger.js":41,"./player-errors.js":34,"./player-events.js":35,"events":2}],33:[function(_dereq_,module,exports){
9545'use strict';
9546
9547Object.defineProperty(exports, "__esModule", {
9548 value: true
9549});
9550
9551var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
9552
9553var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
9554 * Copyright (C) 2016 Bilibili. All Rights Reserved.
9555 *
9556 * @author zheng qian <xqq@xqq.im>
9557 *
9558 * Licensed under the Apache License, Version 2.0 (the "License");
9559 * you may not use this file except in compliance with the License.
9560 * You may obtain a copy of the License at
9561 *
9562 * http://www.apache.org/licenses/LICENSE-2.0
9563 *
9564 * Unless required by applicable law or agreed to in writing, software
9565 * distributed under the License is distributed on an "AS IS" BASIS,
9566 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9567 * See the License for the specific language governing permissions and
9568 * limitations under the License.
9569 */
9570
9571var _events = _dereq_('events');
9572
9573var _events2 = _interopRequireDefault(_events);
9574
9575var _playerEvents = _dereq_('./player-events.js');
9576
9577var _playerEvents2 = _interopRequireDefault(_playerEvents);
9578
9579var _config = _dereq_('../config.js');
9580
9581var _exception = _dereq_('../utils/exception.js');
9582
9583function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9584
9585function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
9586
9587// Player wrapper for browser's native player (HTMLVideoElement) without MediaSource src.
9588var NativePlayer = function () {
9589 function NativePlayer(mediaDataSource, config) {
9590 _classCallCheck(this, NativePlayer);
9591
9592 this.TAG = 'NativePlayer';
9593 this._type = 'NativePlayer';
9594 this._emitter = new _events2.default();
9595
9596 this._config = (0, _config.createDefaultConfig)();
9597 if ((typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object') {
9598 Object.assign(this._config, config);
9599 }
9600
9601 if (mediaDataSource.type.toLowerCase() === 'flv') {
9602 throw new _exception.InvalidArgumentException('NativePlayer does\'t support flv MediaDataSource input!');
9603 }
9604 if (mediaDataSource.hasOwnProperty('segments')) {
9605 throw new _exception.InvalidArgumentException('NativePlayer(' + mediaDataSource.type + ') doesn\'t support multipart playback!');
9606 }
9607
9608 this.e = {
9609 onvLoadedMetadata: this._onvLoadedMetadata.bind(this)
9610 };
9611
9612 this._pendingSeekTime = null;
9613 this._statisticsReporter = null;
9614
9615 this._mediaDataSource = mediaDataSource;
9616 this._mediaElement = null;
9617 }
9618
9619 _createClass(NativePlayer, [{
9620 key: 'destroy',
9621 value: function destroy() {
9622 if (this._mediaElement) {
9623 this.unload();
9624 this.detachMediaElement();
9625 }
9626 this.e = null;
9627 this._mediaDataSource = null;
9628 this._emitter.removeAllListeners();
9629 this._emitter = null;
9630 }
9631 }, {
9632 key: 'on',
9633 value: function on(event, listener) {
9634 var _this = this;
9635
9636 if (event === _playerEvents2.default.MEDIA_INFO) {
9637 if (this._mediaElement != null && this._mediaElement.readyState !== 0) {
9638 // HAVE_NOTHING
9639 Promise.resolve().then(function () {
9640 _this._emitter.emit(_playerEvents2.default.MEDIA_INFO, _this.mediaInfo);
9641 });
9642 }
9643 } else if (event === _playerEvents2.default.STATISTICS_INFO) {
9644 if (this._mediaElement != null && this._mediaElement.readyState !== 0) {
9645 Promise.resolve().then(function () {
9646 _this._emitter.emit(_playerEvents2.default.STATISTICS_INFO, _this.statisticsInfo);
9647 });
9648 }
9649 }
9650 this._emitter.addListener(event, listener);
9651 }
9652 }, {
9653 key: 'off',
9654 value: function off(event, listener) {
9655 this._emitter.removeListener(event, listener);
9656 }
9657 }, {
9658 key: 'attachMediaElement',
9659 value: function attachMediaElement(mediaElement) {
9660 this._mediaElement = mediaElement;
9661 mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata);
9662
9663 if (this._pendingSeekTime != null) {
9664 try {
9665 mediaElement.currentTime = this._pendingSeekTime;
9666 this._pendingSeekTime = null;
9667 } catch (e) {
9668 // IE11 may throw InvalidStateError if readyState === 0
9669 // Defer set currentTime operation after loadedmetadata
9670 }
9671 }
9672 }
9673 }, {
9674 key: 'detachMediaElement',
9675 value: function detachMediaElement() {
9676 if (this._mediaElement) {
9677 this._mediaElement.src = '';
9678 this._mediaElement.removeAttribute('src');
9679 this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
9680 this._mediaElement = null;
9681 }
9682 if (this._statisticsReporter != null) {
9683 window.clearInterval(this._statisticsReporter);
9684 this._statisticsReporter = null;
9685 }
9686 }
9687 }, {
9688 key: 'load',
9689 value: function load() {
9690 if (!this._mediaElement) {
9691 throw new _exception.IllegalStateException('HTMLMediaElement must be attached before load()!');
9692 }
9693 this._mediaElement.src = this._mediaDataSource.url;
9694
9695 if (this._mediaElement.readyState > 0) {
9696 this._mediaElement.currentTime = 0;
9697 }
9698
9699 this._mediaElement.preload = 'auto';
9700 this._mediaElement.load();
9701 this._statisticsReporter = window.setInterval(this._reportStatisticsInfo.bind(this), this._config.statisticsInfoReportInterval);
9702 }
9703 }, {
9704 key: 'unload',
9705 value: function unload() {
9706 if (this._mediaElement) {
9707 this._mediaElement.src = '';
9708 this._mediaElement.removeAttribute('src');
9709 }
9710 if (this._statisticsReporter != null) {
9711 window.clearInterval(this._statisticsReporter);
9712 this._statisticsReporter = null;
9713 }
9714 }
9715 }, {
9716 key: 'play',
9717 value: function play() {
9718 return this._mediaElement.play();
9719 }
9720 }, {
9721 key: 'pause',
9722 value: function pause() {
9723 this._mediaElement.pause();
9724 }
9725 }, {
9726 key: '_onvLoadedMetadata',
9727 value: function _onvLoadedMetadata(e) {
9728 if (this._pendingSeekTime != null) {
9729 this._mediaElement.currentTime = this._pendingSeekTime;
9730 this._pendingSeekTime = null;
9731 }
9732 this._emitter.emit(_playerEvents2.default.MEDIA_INFO, this.mediaInfo);
9733 }
9734 }, {
9735 key: '_reportStatisticsInfo',
9736 value: function _reportStatisticsInfo() {
9737 this._emitter.emit(_playerEvents2.default.STATISTICS_INFO, this.statisticsInfo);
9738 }
9739 }, {
9740 key: 'type',
9741 get: function get() {
9742 return this._type;
9743 }
9744 }, {
9745 key: 'buffered',
9746 get: function get() {
9747 return this._mediaElement.buffered;
9748 }
9749 }, {
9750 key: 'duration',
9751 get: function get() {
9752 return this._mediaElement.duration;
9753 }
9754 }, {
9755 key: 'volume',
9756 get: function get() {
9757 return this._mediaElement.volume;
9758 },
9759 set: function set(value) {
9760 this._mediaElement.volume = value;
9761 }
9762 }, {
9763 key: 'muted',
9764 get: function get() {
9765 return this._mediaElement.muted;
9766 },
9767 set: function set(muted) {
9768 this._mediaElement.muted = muted;
9769 }
9770 }, {
9771 key: 'currentTime',
9772 get: function get() {
9773 if (this._mediaElement) {
9774 return this._mediaElement.currentTime;
9775 }
9776 return 0;
9777 },
9778 set: function set(seconds) {
9779 if (this._mediaElement) {
9780 this._mediaElement.currentTime = seconds;
9781 } else {
9782 this._pendingSeekTime = seconds;
9783 }
9784 }
9785 }, {
9786 key: 'mediaInfo',
9787 get: function get() {
9788 var mediaPrefix = this._mediaElement instanceof HTMLAudioElement ? 'audio/' : 'video/';
9789 var info = {
9790 mimeType: mediaPrefix + this._mediaDataSource.type
9791 };
9792 if (this._mediaElement) {
9793 info.duration = Math.floor(this._mediaElement.duration * 1000);
9794 if (this._mediaElement instanceof HTMLVideoElement) {
9795 info.width = this._mediaElement.videoWidth;
9796 info.height = this._mediaElement.videoHeight;
9797 }
9798 }
9799 return info;
9800 }
9801 }, {
9802 key: 'statisticsInfo',
9803 get: function get() {
9804 var info = {
9805 playerType: this._type,
9806 url: this._mediaDataSource.url
9807 };
9808
9809 if (!(this._mediaElement instanceof HTMLVideoElement)) {
9810 return info;
9811 }
9812
9813 var hasQualityInfo = true;
9814 var decoded = 0;
9815 var dropped = 0;
9816
9817 if (this._mediaElement.getVideoPlaybackQuality) {
9818 var quality = this._mediaElement.getVideoPlaybackQuality();
9819 decoded = quality.totalVideoFrames;
9820 dropped = quality.droppedVideoFrames;
9821 } else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
9822 decoded = this._mediaElement.webkitDecodedFrameCount;
9823 dropped = this._mediaElement.webkitDroppedFrameCount;
9824 } else {
9825 hasQualityInfo = false;
9826 }
9827
9828 if (hasQualityInfo) {
9829 info.decodedFrames = decoded;
9830 info.droppedFrames = dropped;
9831 }
9832
9833 return info;
9834 }
9835 }]);
9836
9837 return NativePlayer;
9838}();
9839
9840exports.default = NativePlayer;
9841
9842},{"../config.js":5,"../utils/exception.js":40,"./player-events.js":35,"events":2}],34:[function(_dereq_,module,exports){
9843'use strict';
9844
9845Object.defineProperty(exports, "__esModule", {
9846 value: true
9847});
9848exports.ErrorDetails = exports.ErrorTypes = undefined;
9849
9850var _loader = _dereq_('../io/loader.js');
9851
9852var _demuxErrors = _dereq_('../demux/demux-errors.js');
9853
9854var _demuxErrors2 = _interopRequireDefault(_demuxErrors);
9855
9856function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9857
9858/*
9859 * Copyright (C) 2016 Bilibili. All Rights Reserved.
9860 *
9861 * @author zheng qian <xqq@xqq.im>
9862 *
9863 * Licensed under the Apache License, Version 2.0 (the "License");
9864 * you may not use this file except in compliance with the License.
9865 * You may obtain a copy of the License at
9866 *
9867 * http://www.apache.org/licenses/LICENSE-2.0
9868 *
9869 * Unless required by applicable law or agreed to in writing, software
9870 * distributed under the License is distributed on an "AS IS" BASIS,
9871 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9872 * See the License for the specific language governing permissions and
9873 * limitations under the License.
9874 */
9875
9876var ErrorTypes = exports.ErrorTypes = {
9877 NETWORK_ERROR: 'NetworkError',
9878 MEDIA_ERROR: 'MediaError',
9879 OTHER_ERROR: 'OtherError'
9880};
9881
9882var ErrorDetails = exports.ErrorDetails = {
9883 NETWORK_EXCEPTION: _loader.LoaderErrors.EXCEPTION,
9884 NETWORK_STATUS_CODE_INVALID: _loader.LoaderErrors.HTTP_STATUS_CODE_INVALID,
9885 NETWORK_TIMEOUT: _loader.LoaderErrors.CONNECTING_TIMEOUT,
9886 NETWORK_UNRECOVERABLE_EARLY_EOF: _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF,
9887
9888 MEDIA_MSE_ERROR: 'MediaMSEError',
9889
9890 MEDIA_FORMAT_ERROR: _demuxErrors2.default.FORMAT_ERROR,
9891 MEDIA_FORMAT_UNSUPPORTED: _demuxErrors2.default.FORMAT_UNSUPPORTED,
9892 MEDIA_CODEC_UNSUPPORTED: _demuxErrors2.default.CODEC_UNSUPPORTED
9893};
9894
9895},{"../demux/demux-errors.js":16,"../io/loader.js":24}],35:[function(_dereq_,module,exports){
9896'use strict';
9897
9898Object.defineProperty(exports, "__esModule", {
9899 value: true
9900});
9901/*
9902 * Copyright (C) 2016 Bilibili. All Rights Reserved.
9903 *
9904 * @author zheng qian <xqq@xqq.im>
9905 *
9906 * Licensed under the Apache License, Version 2.0 (the "License");
9907 * you may not use this file except in compliance with the License.
9908 * You may obtain a copy of the License at
9909 *
9910 * http://www.apache.org/licenses/LICENSE-2.0
9911 *
9912 * Unless required by applicable law or agreed to in writing, software
9913 * distributed under the License is distributed on an "AS IS" BASIS,
9914 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9915 * See the License for the specific language governing permissions and
9916 * limitations under the License.
9917 */
9918
9919var PlayerEvents = {
9920 ERROR: 'error',
9921 LOADING_COMPLETE: 'loading_complete',
9922 RECOVERED_EARLY_EOF: 'recovered_early_eof',
9923 MEDIA_INFO: 'media_info',
9924 METADATA_ARRIVED: 'metadata_arrived',
9925 SCRIPTDATA_ARRIVED: 'scriptdata_arrived',
9926 STATISTICS_INFO: 'statistics_info'
9927};
9928
9929exports.default = PlayerEvents;
9930
9931},{}],36:[function(_dereq_,module,exports){
9932'use strict';
9933
9934Object.defineProperty(exports, "__esModule", {
9935 value: true
9936});
9937
9938var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
9939
9940function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
9941
9942/*
9943 * Copyright (C) 2016 Bilibili. All Rights Reserved.
9944 *
9945 * This file is modified from dailymotion's hls.js library (hls.js/src/helper/aac.js)
9946 * @author zheng qian <xqq@xqq.im>
9947 *
9948 * Licensed under the Apache License, Version 2.0 (the "License");
9949 * you may not use this file except in compliance with the License.
9950 * You may obtain a copy of the License at
9951 *
9952 * http://www.apache.org/licenses/LICENSE-2.0
9953 *
9954 * Unless required by applicable law or agreed to in writing, software
9955 * distributed under the License is distributed on an "AS IS" BASIS,
9956 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9957 * See the License for the specific language governing permissions and
9958 * limitations under the License.
9959 */
9960
9961var AAC = function () {
9962 function AAC() {
9963 _classCallCheck(this, AAC);
9964 }
9965
9966 _createClass(AAC, null, [{
9967 key: 'getSilentFrame',
9968 value: function getSilentFrame(codec, channelCount) {
9969 if (codec === 'mp4a.40.2') {
9970 // handle LC-AAC
9971 if (channelCount === 1) {
9972 return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x23, 0x80]);
9973 } else if (channelCount === 2) {
9974 return new Uint8Array([0x21, 0x00, 0x49, 0x90, 0x02, 0x19, 0x00, 0x23, 0x80]);
9975 } else if (channelCount === 3) {
9976 return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x8e]);
9977 } else if (channelCount === 4) {
9978 return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x80, 0x2c, 0x80, 0x08, 0x02, 0x38]);
9979 } else if (channelCount === 5) {
9980 return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x82, 0x30, 0x04, 0x99, 0x00, 0x21, 0x90, 0x02, 0x38]);
9981 } else if (channelCount === 6) {
9982 return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x82, 0x30, 0x04, 0x99, 0x00, 0x21, 0x90, 0x02, 0x00, 0xb2, 0x00, 0x20, 0x08, 0xe0]);
9983 }
9984 } else {
9985 // handle HE-AAC (mp4a.40.5 / mp4a.40.29)
9986 if (channelCount === 1) {
9987 // ffmpeg -y -f lavfi -i "aevalsrc=0:d=0.05" -c:a libfdk_aac -profile:a aac_he -b:a 4k output.aac && hexdump -v -e '16/1 "0x%x," "\n"' -v output.aac
9988 return new Uint8Array([0x1, 0x40, 0x22, 0x80, 0xa3, 0x4e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x1c, 0x6, 0xf1, 0xc1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e]);
9989 } else if (channelCount === 2) {
9990 // ffmpeg -y -f lavfi -i "aevalsrc=0|0:d=0.05" -c:a libfdk_aac -profile:a aac_he_v2 -b:a 4k output.aac && hexdump -v -e '16/1 "0x%x," "\n"' -v output.aac
9991 return new Uint8Array([0x1, 0x40, 0x22, 0x80, 0xa3, 0x5e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x0, 0x95, 0x0, 0x6, 0xf1, 0xa1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e]);
9992 } else if (channelCount === 3) {
9993 // ffmpeg -y -f lavfi -i "aevalsrc=0|0|0:d=0.05" -c:a libfdk_aac -profile:a aac_he_v2 -b:a 4k output.aac && hexdump -v -e '16/1 "0x%x," "\n"' -v output.aac
9994 return new Uint8Array([0x1, 0x40, 0x22, 0x80, 0xa3, 0x5e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x0, 0x95, 0x0, 0x6, 0xf1, 0xa1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e]);
9995 }
9996 }
9997 return null;
9998 }
9999 }]);
10000
10001 return AAC;
10002}();
10003
10004exports.default = AAC;
10005
10006},{}],37:[function(_dereq_,module,exports){
10007'use strict';
10008
10009Object.defineProperty(exports, "__esModule", {
10010 value: true
10011});
10012
10013var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
10014
10015function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10016
10017/*
10018 * Copyright (C) 2016 Bilibili. All Rights Reserved.
10019 *
10020 * This file is derived from dailymotion's hls.js library (hls.js/src/remux/mp4-generator.js)
10021 * @author zheng qian <xqq@xqq.im>
10022 *
10023 * Licensed under the Apache License, Version 2.0 (the "License");
10024 * you may not use this file except in compliance with the License.
10025 * You may obtain a copy of the License at
10026 *
10027 * http://www.apache.org/licenses/LICENSE-2.0
10028 *
10029 * Unless required by applicable law or agreed to in writing, software
10030 * distributed under the License is distributed on an "AS IS" BASIS,
10031 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10032 * See the License for the specific language governing permissions and
10033 * limitations under the License.
10034 */
10035
10036// MP4 boxes generator for ISO BMFF (ISO Base Media File Format, defined in ISO/IEC 14496-12)
10037var MP4 = function () {
10038 function MP4() {
10039 _classCallCheck(this, MP4);
10040 }
10041
10042 _createClass(MP4, null, [{
10043 key: 'init',
10044 value: function init() {
10045 MP4.types = {
10046 avc1: [], avcC: [], btrt: [], dinf: [],
10047 dref: [], esds: [], ftyp: [], hdlr: [],
10048 mdat: [], mdhd: [], mdia: [], mfhd: [],
10049 minf: [], moof: [], moov: [], mp4a: [],
10050 mvex: [], mvhd: [], sdtp: [], stbl: [],
10051 stco: [], stsc: [], stsd: [], stsz: [],
10052 stts: [], tfdt: [], tfhd: [], traf: [],
10053 trak: [], trun: [], trex: [], tkhd: [],
10054 vmhd: [], smhd: [], '.mp3': []
10055 };
10056
10057 for (var name in MP4.types) {
10058 if (MP4.types.hasOwnProperty(name)) {
10059 MP4.types[name] = [name.charCodeAt(0), name.charCodeAt(1), name.charCodeAt(2), name.charCodeAt(3)];
10060 }
10061 }
10062
10063 var constants = MP4.constants = {};
10064
10065 constants.FTYP = new Uint8Array([0x69, 0x73, 0x6F, 0x6D, // major_brand: isom
10066 0x0, 0x0, 0x0, 0x1, // minor_version: 0x01
10067 0x69, 0x73, 0x6F, 0x6D, // isom
10068 0x61, 0x76, 0x63, 0x31 // avc1
10069 ]);
10070
10071 constants.STSD_PREFIX = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10072 0x00, 0x00, 0x00, 0x01 // entry_count
10073 ]);
10074
10075 constants.STTS = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10076 0x00, 0x00, 0x00, 0x00 // entry_count
10077 ]);
10078
10079 constants.STSC = constants.STCO = constants.STTS;
10080
10081 constants.STSZ = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10082 0x00, 0x00, 0x00, 0x00, // sample_size
10083 0x00, 0x00, 0x00, 0x00 // sample_count
10084 ]);
10085
10086 constants.HDLR_VIDEO = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10087 0x00, 0x00, 0x00, 0x00, // pre_defined
10088 0x76, 0x69, 0x64, 0x65, // handler_type: 'vide'
10089 0x00, 0x00, 0x00, 0x00, // reserved: 3 * 4 bytes
10090 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x69, 0x64, 0x65, 0x6F, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00 // name: VideoHandler
10091 ]);
10092
10093 constants.HDLR_AUDIO = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10094 0x00, 0x00, 0x00, 0x00, // pre_defined
10095 0x73, 0x6F, 0x75, 0x6E, // handler_type: 'soun'
10096 0x00, 0x00, 0x00, 0x00, // reserved: 3 * 4 bytes
10097 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x6F, 0x75, 0x6E, 0x64, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00 // name: SoundHandler
10098 ]);
10099
10100 constants.DREF = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10101 0x00, 0x00, 0x00, 0x01, // entry_count
10102 0x00, 0x00, 0x00, 0x0C, // entry_size
10103 0x75, 0x72, 0x6C, 0x20, // type 'url '
10104 0x00, 0x00, 0x00, 0x01 // version(0) + flags
10105 ]);
10106
10107 // Sound media header
10108 constants.SMHD = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10109 0x00, 0x00, 0x00, 0x00 // balance(2) + reserved(2)
10110 ]);
10111
10112 // video media header
10113 constants.VMHD = new Uint8Array([0x00, 0x00, 0x00, 0x01, // version(0) + flags
10114 0x00, 0x00, // graphicsmode: 2 bytes
10115 0x00, 0x00, 0x00, 0x00, // opcolor: 3 * 2 bytes
10116 0x00, 0x00]);
10117 }
10118
10119 // Generate a box
10120
10121 }, {
10122 key: 'box',
10123 value: function box(type) {
10124 var size = 8;
10125 var result = null;
10126 var datas = Array.prototype.slice.call(arguments, 1);
10127 var arrayCount = datas.length;
10128
10129 for (var i = 0; i < arrayCount; i++) {
10130 size += datas[i].byteLength;
10131 }
10132
10133 result = new Uint8Array(size);
10134 result[0] = size >>> 24 & 0xFF; // size
10135 result[1] = size >>> 16 & 0xFF;
10136 result[2] = size >>> 8 & 0xFF;
10137 result[3] = size & 0xFF;
10138
10139 result.set(type, 4); // type
10140
10141 var offset = 8;
10142 for (var _i = 0; _i < arrayCount; _i++) {
10143 // data body
10144 result.set(datas[_i], offset);
10145 offset += datas[_i].byteLength;
10146 }
10147
10148 return result;
10149 }
10150
10151 // emit ftyp & moov
10152
10153 }, {
10154 key: 'generateInitSegment',
10155 value: function generateInitSegment(meta) {
10156 var ftyp = MP4.box(MP4.types.ftyp, MP4.constants.FTYP);
10157 var moov = MP4.moov(meta);
10158
10159 var result = new Uint8Array(ftyp.byteLength + moov.byteLength);
10160 result.set(ftyp, 0);
10161 result.set(moov, ftyp.byteLength);
10162 return result;
10163 }
10164
10165 // Movie metadata box
10166
10167 }, {
10168 key: 'moov',
10169 value: function moov(meta) {
10170 var mvhd = MP4.mvhd(meta.timescale, meta.duration);
10171 var trak = MP4.trak(meta);
10172 var mvex = MP4.mvex(meta);
10173 return MP4.box(MP4.types.moov, mvhd, trak, mvex);
10174 }
10175
10176 // Movie header box
10177
10178 }, {
10179 key: 'mvhd',
10180 value: function mvhd(timescale, duration) {
10181 return MP4.box(MP4.types.mvhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10182 0x00, 0x00, 0x00, 0x00, // creation_time
10183 0x00, 0x00, 0x00, 0x00, // modification_time
10184 timescale >>> 24 & 0xFF, // timescale: 4 bytes
10185 timescale >>> 16 & 0xFF, timescale >>> 8 & 0xFF, timescale & 0xFF, duration >>> 24 & 0xFF, // duration: 4 bytes
10186 duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, 0x00, 0x01, 0x00, 0x00, // Preferred rate: 1.0
10187 0x01, 0x00, 0x00, 0x00, // PreferredVolume(1.0, 2bytes) + reserved(2bytes)
10188 0x00, 0x00, 0x00, 0x00, // reserved: 4 + 4 bytes
10189 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ----begin composition matrix----
10190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // ----end composition matrix----
10191 0x00, 0x00, 0x00, 0x00, // ----begin pre_defined 6 * 4 bytes----
10192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ----end pre_defined 6 * 4 bytes----
10193 0xFF, 0xFF, 0xFF, 0xFF // next_track_ID
10194 ]));
10195 }
10196
10197 // Track box
10198
10199 }, {
10200 key: 'trak',
10201 value: function trak(meta) {
10202 return MP4.box(MP4.types.trak, MP4.tkhd(meta), MP4.mdia(meta));
10203 }
10204
10205 // Track header box
10206
10207 }, {
10208 key: 'tkhd',
10209 value: function tkhd(meta) {
10210 var trackId = meta.id,
10211 duration = meta.duration;
10212 var width = meta.presentWidth,
10213 height = meta.presentHeight;
10214
10215 return MP4.box(MP4.types.tkhd, new Uint8Array([0x00, 0x00, 0x00, 0x07, // version(0) + flags
10216 0x00, 0x00, 0x00, 0x00, // creation_time
10217 0x00, 0x00, 0x00, 0x00, // modification_time
10218 trackId >>> 24 & 0xFF, // track_ID: 4 bytes
10219 trackId >>> 16 & 0xFF, trackId >>> 8 & 0xFF, trackId & 0xFF, 0x00, 0x00, 0x00, 0x00, // reserved: 4 bytes
10220 duration >>> 24 & 0xFF, // duration: 4 bytes
10221 duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, 0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
10222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // layer(2bytes) + alternate_group(2bytes)
10223 0x00, 0x00, 0x00, 0x00, // volume(2bytes) + reserved(2bytes)
10224 0x00, 0x01, 0x00, 0x00, // ----begin composition matrix----
10225 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // ----end composition matrix----
10226 width >>> 8 & 0xFF, // width and height
10227 width & 0xFF, 0x00, 0x00, height >>> 8 & 0xFF, height & 0xFF, 0x00, 0x00]));
10228 }
10229
10230 // Media Box
10231
10232 }, {
10233 key: 'mdia',
10234 value: function mdia(meta) {
10235 return MP4.box(MP4.types.mdia, MP4.mdhd(meta), MP4.hdlr(meta), MP4.minf(meta));
10236 }
10237
10238 // Media header box
10239
10240 }, {
10241 key: 'mdhd',
10242 value: function mdhd(meta) {
10243 var timescale = meta.timescale;
10244 var duration = meta.duration;
10245 return MP4.box(MP4.types.mdhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10246 0x00, 0x00, 0x00, 0x00, // creation_time
10247 0x00, 0x00, 0x00, 0x00, // modification_time
10248 timescale >>> 24 & 0xFF, // timescale: 4 bytes
10249 timescale >>> 16 & 0xFF, timescale >>> 8 & 0xFF, timescale & 0xFF, duration >>> 24 & 0xFF, // duration: 4 bytes
10250 duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, 0x55, 0xC4, // language: und (undetermined)
10251 0x00, 0x00 // pre_defined = 0
10252 ]));
10253 }
10254
10255 // Media handler reference box
10256
10257 }, {
10258 key: 'hdlr',
10259 value: function hdlr(meta) {
10260 var data = null;
10261 if (meta.type === 'audio') {
10262 data = MP4.constants.HDLR_AUDIO;
10263 } else {
10264 data = MP4.constants.HDLR_VIDEO;
10265 }
10266 return MP4.box(MP4.types.hdlr, data);
10267 }
10268
10269 // Media infomation box
10270
10271 }, {
10272 key: 'minf',
10273 value: function minf(meta) {
10274 var xmhd = null;
10275 if (meta.type === 'audio') {
10276 xmhd = MP4.box(MP4.types.smhd, MP4.constants.SMHD);
10277 } else {
10278 xmhd = MP4.box(MP4.types.vmhd, MP4.constants.VMHD);
10279 }
10280 return MP4.box(MP4.types.minf, xmhd, MP4.dinf(), MP4.stbl(meta));
10281 }
10282
10283 // Data infomation box
10284
10285 }, {
10286 key: 'dinf',
10287 value: function dinf() {
10288 var result = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, MP4.constants.DREF));
10289 return result;
10290 }
10291
10292 // Sample table box
10293
10294 }, {
10295 key: 'stbl',
10296 value: function stbl(meta) {
10297 var result = MP4.box(MP4.types.stbl, // type: stbl
10298 MP4.stsd(meta), // Sample Description Table
10299 MP4.box(MP4.types.stts, MP4.constants.STTS), // Time-To-Sample
10300 MP4.box(MP4.types.stsc, MP4.constants.STSC), // Sample-To-Chunk
10301 MP4.box(MP4.types.stsz, MP4.constants.STSZ), // Sample size
10302 MP4.box(MP4.types.stco, MP4.constants.STCO // Chunk offset
10303 ));
10304 return result;
10305 }
10306
10307 // Sample description box
10308
10309 }, {
10310 key: 'stsd',
10311 value: function stsd(meta) {
10312 if (meta.type === 'audio') {
10313 if (meta.codec === 'mp3') {
10314 return MP4.box(MP4.types.stsd, MP4.constants.STSD_PREFIX, MP4.mp3(meta));
10315 }
10316 // else: aac -> mp4a
10317 return MP4.box(MP4.types.stsd, MP4.constants.STSD_PREFIX, MP4.mp4a(meta));
10318 } else {
10319 return MP4.box(MP4.types.stsd, MP4.constants.STSD_PREFIX, MP4.avc1(meta));
10320 }
10321 }
10322 }, {
10323 key: 'mp3',
10324 value: function mp3(meta) {
10325 var channelCount = meta.channelCount;
10326 var sampleRate = meta.audioSampleRate;
10327
10328 var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // reserved(4)
10329 0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
10330 0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
10331 0x00, 0x00, 0x00, 0x00, 0x00, channelCount, // channelCount(2)
10332 0x00, 0x10, // sampleSize(2)
10333 0x00, 0x00, 0x00, 0x00, // reserved(4)
10334 sampleRate >>> 8 & 0xFF, // Audio sample rate
10335 sampleRate & 0xFF, 0x00, 0x00]);
10336
10337 return MP4.box(MP4.types['.mp3'], data);
10338 }
10339 }, {
10340 key: 'mp4a',
10341 value: function mp4a(meta) {
10342 var channelCount = meta.channelCount;
10343 var sampleRate = meta.audioSampleRate;
10344
10345 var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // reserved(4)
10346 0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
10347 0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
10348 0x00, 0x00, 0x00, 0x00, 0x00, channelCount, // channelCount(2)
10349 0x00, 0x10, // sampleSize(2)
10350 0x00, 0x00, 0x00, 0x00, // reserved(4)
10351 sampleRate >>> 8 & 0xFF, // Audio sample rate
10352 sampleRate & 0xFF, 0x00, 0x00]);
10353
10354 return MP4.box(MP4.types.mp4a, data, MP4.esds(meta));
10355 }
10356 }, {
10357 key: 'esds',
10358 value: function esds(meta) {
10359 var config = meta.config || [];
10360 var configSize = config.length;
10361 var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version 0 + flags
10362
10363 0x03, // descriptor_type
10364 0x17 + configSize, // length3
10365 0x00, 0x01, // es_id
10366 0x00, // stream_priority
10367
10368 0x04, // descriptor_type
10369 0x0F + configSize, // length
10370 0x40, // codec: mpeg4_audio
10371 0x15, // stream_type: Audio
10372 0x00, 0x00, 0x00, // buffer_size
10373 0x00, 0x00, 0x00, 0x00, // maxBitrate
10374 0x00, 0x00, 0x00, 0x00, // avgBitrate
10375
10376 0x05 // descriptor_type
10377 ].concat([configSize]).concat(config).concat([0x06, 0x01, 0x02 // GASpecificConfig
10378 ]));
10379 return MP4.box(MP4.types.esds, data);
10380 }
10381 }, {
10382 key: 'avc1',
10383 value: function avc1(meta) {
10384 var avcc = meta.avcc;
10385 var width = meta.codecWidth,
10386 height = meta.codecHeight;
10387
10388 var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // reserved(4)
10389 0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
10390 0x00, 0x00, 0x00, 0x00, // pre_defined(2) + reserved(2)
10391 0x00, 0x00, 0x00, 0x00, // pre_defined: 3 * 4 bytes
10392 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, width >>> 8 & 0xFF, // width: 2 bytes
10393 width & 0xFF, height >>> 8 & 0xFF, // height: 2 bytes
10394 height & 0xFF, 0x00, 0x48, 0x00, 0x00, // horizresolution: 4 bytes
10395 0x00, 0x48, 0x00, 0x00, // vertresolution: 4 bytes
10396 0x00, 0x00, 0x00, 0x00, // reserved: 4 bytes
10397 0x00, 0x01, // frame_count
10398 0x0A, // strlen
10399 0x78, 0x71, 0x71, 0x2F, // compressorname: 32 bytes
10400 0x66, 0x6C, 0x76, 0x2E, 0x6A, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, // depth
10401 0xFF, 0xFF // pre_defined = -1
10402 ]);
10403 return MP4.box(MP4.types.avc1, data, MP4.box(MP4.types.avcC, avcc));
10404 }
10405
10406 // Movie Extends box
10407
10408 }, {
10409 key: 'mvex',
10410 value: function mvex(meta) {
10411 return MP4.box(MP4.types.mvex, MP4.trex(meta));
10412 }
10413
10414 // Track Extends box
10415
10416 }, {
10417 key: 'trex',
10418 value: function trex(meta) {
10419 var trackId = meta.id;
10420 var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
10421 trackId >>> 24 & 0xFF, // track_ID
10422 trackId >>> 16 & 0xFF, trackId >>> 8 & 0xFF, trackId & 0xFF, 0x00, 0x00, 0x00, 0x01, // default_sample_description_index
10423 0x00, 0x00, 0x00, 0x00, // default_sample_duration
10424 0x00, 0x00, 0x00, 0x00, // default_sample_size
10425 0x00, 0x01, 0x00, 0x01 // default_sample_flags
10426 ]);
10427 return MP4.box(MP4.types.trex, data);
10428 }
10429
10430 // Movie fragment box
10431
10432 }, {
10433 key: 'moof',
10434 value: function moof(track, baseMediaDecodeTime) {
10435 return MP4.box(MP4.types.moof, MP4.mfhd(track.sequenceNumber), MP4.traf(track, baseMediaDecodeTime));
10436 }
10437 }, {
10438 key: 'mfhd',
10439 value: function mfhd(sequenceNumber) {
10440 var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, sequenceNumber >>> 24 & 0xFF, // sequence_number: int32
10441 sequenceNumber >>> 16 & 0xFF, sequenceNumber >>> 8 & 0xFF, sequenceNumber & 0xFF]);
10442 return MP4.box(MP4.types.mfhd, data);
10443 }
10444
10445 // Track fragment box
10446
10447 }, {
10448 key: 'traf',
10449 value: function traf(track, baseMediaDecodeTime) {
10450 var trackId = track.id;
10451
10452 // Track fragment header box
10453 var tfhd = MP4.box(MP4.types.tfhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) & flags
10454 trackId >>> 24 & 0xFF, // track_ID
10455 trackId >>> 16 & 0xFF, trackId >>> 8 & 0xFF, trackId & 0xFF]));
10456 // Track Fragment Decode Time
10457 var tfdt = MP4.box(MP4.types.tfdt, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) & flags
10458 baseMediaDecodeTime >>> 24 & 0xFF, // baseMediaDecodeTime: int32
10459 baseMediaDecodeTime >>> 16 & 0xFF, baseMediaDecodeTime >>> 8 & 0xFF, baseMediaDecodeTime & 0xFF]));
10460 var sdtp = MP4.sdtp(track);
10461 var trun = MP4.trun(track, sdtp.byteLength + 16 + 16 + 8 + 16 + 8 + 8);
10462
10463 return MP4.box(MP4.types.traf, tfhd, tfdt, trun, sdtp);
10464 }
10465
10466 // Sample Dependency Type box
10467
10468 }, {
10469 key: 'sdtp',
10470 value: function sdtp(track) {
10471 var samples = track.samples || [];
10472 var sampleCount = samples.length;
10473 var data = new Uint8Array(4 + sampleCount);
10474 // 0~4 bytes: version(0) & flags
10475 for (var i = 0; i < sampleCount; i++) {
10476 var flags = samples[i].flags;
10477 data[i + 4] = flags.isLeading << 6 | // is_leading: 2 (bit)
10478 flags.dependsOn << 4 // sample_depends_on
10479 | flags.isDependedOn << 2 // sample_is_depended_on
10480 | flags.hasRedundancy; // sample_has_redundancy
10481 }
10482 return MP4.box(MP4.types.sdtp, data);
10483 }
10484
10485 // Track fragment run box
10486
10487 }, {
10488 key: 'trun',
10489 value: function trun(track, offset) {
10490 var samples = track.samples || [];
10491 var sampleCount = samples.length;
10492 var dataSize = 12 + 16 * sampleCount;
10493 var data = new Uint8Array(dataSize);
10494 offset += 8 + dataSize;
10495
10496 data.set([0x00, 0x00, 0x0F, 0x01, // version(0) & flags
10497 sampleCount >>> 24 & 0xFF, // sample_count
10498 sampleCount >>> 16 & 0xFF, sampleCount >>> 8 & 0xFF, sampleCount & 0xFF, offset >>> 24 & 0xFF, // data_offset
10499 offset >>> 16 & 0xFF, offset >>> 8 & 0xFF, offset & 0xFF], 0);
10500
10501 for (var i = 0; i < sampleCount; i++) {
10502 var duration = samples[i].duration;
10503 var size = samples[i].size;
10504 var flags = samples[i].flags;
10505 var cts = samples[i].cts;
10506 data.set([duration >>> 24 & 0xFF, // sample_duration
10507 duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, size >>> 24 & 0xFF, // sample_size
10508 size >>> 16 & 0xFF, size >>> 8 & 0xFF, size & 0xFF, flags.isLeading << 2 | flags.dependsOn, // sample_flags
10509 flags.isDependedOn << 6 | flags.hasRedundancy << 4 | flags.isNonSync, 0x00, 0x00, // sample_degradation_priority
10510 cts >>> 24 & 0xFF, // sample_composition_time_offset
10511 cts >>> 16 & 0xFF, cts >>> 8 & 0xFF, cts & 0xFF], 12 + 16 * i);
10512 }
10513 return MP4.box(MP4.types.trun, data);
10514 }
10515 }, {
10516 key: 'mdat',
10517 value: function mdat(data) {
10518 return MP4.box(MP4.types.mdat, data);
10519 }
10520 }]);
10521
10522 return MP4;
10523}();
10524
10525MP4.init();
10526
10527exports.default = MP4;
10528
10529},{}],38:[function(_dereq_,module,exports){
10530'use strict';
10531
10532Object.defineProperty(exports, "__esModule", {
10533 value: true
10534});
10535
10536var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
10537 * Copyright (C) 2016 Bilibili. All Rights Reserved.
10538 *
10539 * @author zheng qian <xqq@xqq.im>
10540 *
10541 * Licensed under the Apache License, Version 2.0 (the "License");
10542 * you may not use this file except in compliance with the License.
10543 * You may obtain a copy of the License at
10544 *
10545 * http://www.apache.org/licenses/LICENSE-2.0
10546 *
10547 * Unless required by applicable law or agreed to in writing, software
10548 * distributed under the License is distributed on an "AS IS" BASIS,
10549 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10550 * See the License for the specific language governing permissions and
10551 * limitations under the License.
10552 */
10553
10554var _logger = _dereq_('../utils/logger.js');
10555
10556var _logger2 = _interopRequireDefault(_logger);
10557
10558var _mp4Generator = _dereq_('./mp4-generator.js');
10559
10560var _mp4Generator2 = _interopRequireDefault(_mp4Generator);
10561
10562var _aacSilent = _dereq_('./aac-silent.js');
10563
10564var _aacSilent2 = _interopRequireDefault(_aacSilent);
10565
10566var _browser = _dereq_('../utils/browser.js');
10567
10568var _browser2 = _interopRequireDefault(_browser);
10569
10570var _mediaSegmentInfo = _dereq_('../core/media-segment-info.js');
10571
10572var _exception = _dereq_('../utils/exception.js');
10573
10574function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10575
10576function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10577
10578// Fragmented mp4 remuxer
10579var MP4Remuxer = function () {
10580 function MP4Remuxer(config) {
10581 _classCallCheck(this, MP4Remuxer);
10582
10583 this.TAG = 'MP4Remuxer';
10584
10585 this._config = config;
10586 this._isLive = config.isLive === true ? true : false;
10587
10588 this._dtsBase = -1;
10589 this._dtsBaseInited = false;
10590 this._audioDtsBase = Infinity;
10591 this._videoDtsBase = Infinity;
10592 this._audioNextDts = undefined;
10593 this._videoNextDts = undefined;
10594 this._audioStashedLastSample = null;
10595 this._videoStashedLastSample = null;
10596
10597 this._audioMeta = null;
10598 this._videoMeta = null;
10599
10600 this._audioSegmentInfoList = new _mediaSegmentInfo.MediaSegmentInfoList('audio');
10601 this._videoSegmentInfoList = new _mediaSegmentInfo.MediaSegmentInfoList('video');
10602
10603 this._onInitSegment = null;
10604 this._onMediaSegment = null;
10605
10606 // Workaround for chrome < 50: Always force first sample as a Random Access Point in media segment
10607 // see https://bugs.chromium.org/p/chromium/issues/detail?id=229412
10608 this._forceFirstIDR = _browser2.default.chrome && (_browser2.default.version.major < 50 || _browser2.default.version.major === 50 && _browser2.default.version.build < 2661) ? true : false;
10609
10610 // Workaround for IE11/Edge: Fill silent aac frame after keyframe-seeking
10611 // Make audio beginDts equals with video beginDts, in order to fix seek freeze
10612 this._fillSilentAfterSeek = _browser2.default.msedge || _browser2.default.msie;
10613
10614 // While only FireFox supports 'audio/mp4, codecs="mp3"', use 'audio/mpeg' for chrome, safari, ...
10615 this._mp3UseMpegAudio = !_browser2.default.firefox;
10616
10617 this._fillAudioTimestampGap = this._config.fixAudioTimestampGap;
10618 }
10619
10620 _createClass(MP4Remuxer, [{
10621 key: 'destroy',
10622 value: function destroy() {
10623 this._dtsBase = -1;
10624 this._dtsBaseInited = false;
10625 this._audioMeta = null;
10626 this._videoMeta = null;
10627 this._audioSegmentInfoList.clear();
10628 this._audioSegmentInfoList = null;
10629 this._videoSegmentInfoList.clear();
10630 this._videoSegmentInfoList = null;
10631 this._onInitSegment = null;
10632 this._onMediaSegment = null;
10633 }
10634 }, {
10635 key: 'bindDataSource',
10636 value: function bindDataSource(producer) {
10637 producer.onDataAvailable = this.remux.bind(this);
10638 producer.onTrackMetadata = this._onTrackMetadataReceived.bind(this);
10639 return this;
10640 }
10641
10642 /* prototype: function onInitSegment(type: string, initSegment: ArrayBuffer): void
10643 InitSegment: {
10644 type: string,
10645 data: ArrayBuffer,
10646 codec: string,
10647 container: string
10648 }
10649 */
10650
10651 }, {
10652 key: 'insertDiscontinuity',
10653 value: function insertDiscontinuity() {
10654 this._audioNextDts = this._videoNextDts = undefined;
10655 }
10656 }, {
10657 key: 'seek',
10658 value: function seek(originalDts) {
10659 this._audioStashedLastSample = null;
10660 this._videoStashedLastSample = null;
10661 this._videoSegmentInfoList.clear();
10662 this._audioSegmentInfoList.clear();
10663 }
10664 }, {
10665 key: 'remux',
10666 value: function remux(audioTrack, videoTrack) {
10667 if (!this._onMediaSegment) {
10668 throw new _exception.IllegalStateException('MP4Remuxer: onMediaSegment callback must be specificed!');
10669 }
10670 if (!this._dtsBaseInited) {
10671 this._calculateDtsBase(audioTrack, videoTrack);
10672 }
10673 this._remuxVideo(videoTrack);
10674 this._remuxAudio(audioTrack);
10675 }
10676 }, {
10677 key: '_onTrackMetadataReceived',
10678 value: function _onTrackMetadataReceived(type, metadata) {
10679 var metabox = null;
10680
10681 var container = 'mp4';
10682 var codec = metadata.codec;
10683
10684 if (type === 'audio') {
10685 this._audioMeta = metadata;
10686 if (metadata.codec === 'mp3' && this._mp3UseMpegAudio) {
10687 // 'audio/mpeg' for MP3 audio track
10688 container = 'mpeg';
10689 codec = '';
10690 metabox = new Uint8Array();
10691 } else {
10692 // 'audio/mp4, codecs="codec"'
10693 metabox = _mp4Generator2.default.generateInitSegment(metadata);
10694 }
10695 } else if (type === 'video') {
10696 this._videoMeta = metadata;
10697 metabox = _mp4Generator2.default.generateInitSegment(metadata);
10698 } else {
10699 return;
10700 }
10701
10702 // dispatch metabox (Initialization Segment)
10703 if (!this._onInitSegment) {
10704 throw new _exception.IllegalStateException('MP4Remuxer: onInitSegment callback must be specified!');
10705 }
10706 this._onInitSegment(type, {
10707 type: type,
10708 data: metabox.buffer,
10709 codec: codec,
10710 container: type + '/' + container,
10711 mediaDuration: metadata.duration // in timescale 1000 (milliseconds)
10712 });
10713 }
10714 }, {
10715 key: '_calculateDtsBase',
10716 value: function _calculateDtsBase(audioTrack, videoTrack) {
10717 if (this._dtsBaseInited) {
10718 return;
10719 }
10720
10721 if (audioTrack.samples && audioTrack.samples.length) {
10722 this._audioDtsBase = audioTrack.samples[0].dts;
10723 }
10724 if (videoTrack.samples && videoTrack.samples.length) {
10725 this._videoDtsBase = videoTrack.samples[0].dts;
10726 }
10727
10728 this._dtsBase = Math.min(this._audioDtsBase, this._videoDtsBase);
10729 this._dtsBaseInited = true;
10730 }
10731 }, {
10732 key: 'flushStashedSamples',
10733 value: function flushStashedSamples() {
10734 var videoSample = this._videoStashedLastSample;
10735 var audioSample = this._audioStashedLastSample;
10736
10737 var videoTrack = {
10738 type: 'video',
10739 id: 1,
10740 sequenceNumber: 0,
10741 samples: [],
10742 length: 0
10743 };
10744
10745 if (videoSample != null) {
10746 videoTrack.samples.push(videoSample);
10747 videoTrack.length = videoSample.length;
10748 }
10749
10750 var audioTrack = {
10751 type: 'audio',
10752 id: 2,
10753 sequenceNumber: 0,
10754 samples: [],
10755 length: 0
10756 };
10757
10758 if (audioSample != null) {
10759 audioTrack.samples.push(audioSample);
10760 audioTrack.length = audioSample.length;
10761 }
10762
10763 this._videoStashedLastSample = null;
10764 this._audioStashedLastSample = null;
10765
10766 this._remuxVideo(videoTrack, true);
10767 this._remuxAudio(audioTrack, true);
10768 }
10769 }, {
10770 key: '_remuxAudio',
10771 value: function _remuxAudio(audioTrack, force) {
10772 if (this._audioMeta == null) {
10773 return;
10774 }
10775
10776 var track = audioTrack;
10777 var samples = track.samples;
10778 var dtsCorrection = undefined;
10779 var firstDts = -1,
10780 lastDts = -1,
10781 lastPts = -1;
10782 var refSampleDuration = this._audioMeta.refSampleDuration;
10783
10784 var mpegRawTrack = this._audioMeta.codec === 'mp3' && this._mp3UseMpegAudio;
10785 var firstSegmentAfterSeek = this._dtsBaseInited && this._audioNextDts === undefined;
10786
10787 var insertPrefixSilentFrame = false;
10788
10789 if (!samples || samples.length === 0) {
10790 return;
10791 }
10792 if (samples.length === 1 && !force) {
10793 // If [sample count in current batch] === 1 && (force != true)
10794 // Ignore and keep in demuxer's queue
10795 return;
10796 } // else if (force === true) do remux
10797
10798 var offset = 0;
10799 var mdatbox = null;
10800 var mdatBytes = 0;
10801
10802 // calculate initial mdat size
10803 if (mpegRawTrack) {
10804 // for raw mpeg buffer
10805 offset = 0;
10806 mdatBytes = track.length;
10807 } else {
10808 // for fmp4 mdat box
10809 offset = 8; // size + type
10810 mdatBytes = 8 + track.length;
10811 }
10812
10813 var lastSample = null;
10814
10815 // Pop the lastSample and waiting for stash
10816 if (samples.length > 1) {
10817 lastSample = samples.pop();
10818 mdatBytes -= lastSample.length;
10819 }
10820
10821 // Insert [stashed lastSample in the previous batch] to the front
10822 if (this._audioStashedLastSample != null) {
10823 var sample = this._audioStashedLastSample;
10824 this._audioStashedLastSample = null;
10825 samples.unshift(sample);
10826 mdatBytes += sample.length;
10827 }
10828
10829 // Stash the lastSample of current batch, waiting for next batch
10830 if (lastSample != null) {
10831 this._audioStashedLastSample = lastSample;
10832 }
10833
10834 var firstSampleOriginalDts = samples[0].dts - this._dtsBase;
10835
10836 // calculate dtsCorrection
10837 if (this._audioNextDts) {
10838 dtsCorrection = firstSampleOriginalDts - this._audioNextDts;
10839 } else {
10840 // this._audioNextDts == undefined
10841 if (this._audioSegmentInfoList.isEmpty()) {
10842 dtsCorrection = 0;
10843 if (this._fillSilentAfterSeek && !this._videoSegmentInfoList.isEmpty()) {
10844 if (this._audioMeta.originalCodec !== 'mp3') {
10845 insertPrefixSilentFrame = true;
10846 }
10847 }
10848 } else {
10849 var _lastSample = this._audioSegmentInfoList.getLastSampleBefore(firstSampleOriginalDts);
10850 if (_lastSample != null) {
10851 var distance = firstSampleOriginalDts - (_lastSample.originalDts + _lastSample.duration);
10852 if (distance <= 3) {
10853 distance = 0;
10854 }
10855 var expectedDts = _lastSample.dts + _lastSample.duration + distance;
10856 dtsCorrection = firstSampleOriginalDts - expectedDts;
10857 } else {
10858 // lastSample == null, cannot found
10859 dtsCorrection = 0;
10860 }
10861 }
10862 }
10863
10864 if (insertPrefixSilentFrame) {
10865 // align audio segment beginDts to match with current video segment's beginDts
10866 var firstSampleDts = firstSampleOriginalDts - dtsCorrection;
10867 var videoSegment = this._videoSegmentInfoList.getLastSegmentBefore(firstSampleOriginalDts);
10868 if (videoSegment != null && videoSegment.beginDts < firstSampleDts) {
10869 var silentUnit = _aacSilent2.default.getSilentFrame(this._audioMeta.originalCodec, this._audioMeta.channelCount);
10870 if (silentUnit) {
10871 var dts = videoSegment.beginDts;
10872 var silentFrameDuration = firstSampleDts - videoSegment.beginDts;
10873 _logger2.default.v(this.TAG, 'InsertPrefixSilentAudio: dts: ' + dts + ', duration: ' + silentFrameDuration);
10874 samples.unshift({ unit: silentUnit, dts: dts, pts: dts });
10875 mdatBytes += silentUnit.byteLength;
10876 } // silentUnit == null: Cannot generate, skip
10877 } else {
10878 insertPrefixSilentFrame = false;
10879 }
10880 }
10881
10882 var mp4Samples = [];
10883
10884 // Correct dts for each sample, and calculate sample duration. Then output to mp4Samples
10885 for (var i = 0; i < samples.length; i++) {
10886 var _sample = samples[i];
10887 var unit = _sample.unit;
10888 var originalDts = _sample.dts - this._dtsBase;
10889 var _dts = originalDts - dtsCorrection;
10890
10891 if (firstDts === -1) {
10892 firstDts = _dts;
10893 }
10894
10895 var sampleDuration = 0;
10896
10897 if (i !== samples.length - 1) {
10898 var nextDts = samples[i + 1].dts - this._dtsBase - dtsCorrection;
10899 sampleDuration = nextDts - _dts;
10900 } else {
10901 // the last sample
10902 if (lastSample != null) {
10903 // use stashed sample's dts to calculate sample duration
10904 var _nextDts = lastSample.dts - this._dtsBase - dtsCorrection;
10905 sampleDuration = _nextDts - _dts;
10906 } else if (mp4Samples.length >= 1) {
10907 // use second last sample duration
10908 sampleDuration = mp4Samples[mp4Samples.length - 1].duration;
10909 } else {
10910 // the only one sample, use reference sample duration
10911 sampleDuration = Math.floor(refSampleDuration);
10912 }
10913 }
10914
10915 var needFillSilentFrames = false;
10916 var silentFrames = null;
10917
10918 // Silent frame generation, if large timestamp gap detected && config.fixAudioTimestampGap
10919 if (sampleDuration > refSampleDuration * 1.5 && this._audioMeta.codec !== 'mp3' && this._fillAudioTimestampGap && !_browser2.default.safari) {
10920 // We need to insert silent frames to fill timestamp gap
10921 needFillSilentFrames = true;
10922 var delta = Math.abs(sampleDuration - refSampleDuration);
10923 var frameCount = Math.ceil(delta / refSampleDuration);
10924 var currentDts = _dts + refSampleDuration; // Notice: in float
10925
10926 _logger2.default.w(this.TAG, 'Large audio timestamp gap detected, may cause AV sync to drift. ' + 'Silent frames will be generated to avoid unsync.\n' + ('dts: ' + (_dts + sampleDuration) + ' ms, expected: ' + (_dts + Math.round(refSampleDuration)) + ' ms, ') + ('delta: ' + Math.round(delta) + ' ms, generate: ' + frameCount + ' frames'));
10927
10928 var _silentUnit = _aacSilent2.default.getSilentFrame(this._audioMeta.originalCodec, this._audioMeta.channelCount);
10929 if (_silentUnit == null) {
10930 _logger2.default.w(this.TAG, 'Unable to generate silent frame for ' + (this._audioMeta.originalCodec + ' with ' + this._audioMeta.channelCount + ' channels, repeat last frame'));
10931 // Repeat last frame
10932 _silentUnit = unit;
10933 }
10934 silentFrames = [];
10935
10936 for (var j = 0; j < frameCount; j++) {
10937 var intDts = Math.round(currentDts); // round to integer
10938 if (silentFrames.length > 0) {
10939 // Set previous frame sample duration
10940 var previousFrame = silentFrames[silentFrames.length - 1];
10941 previousFrame.duration = intDts - previousFrame.dts;
10942 }
10943 var frame = {
10944 dts: intDts,
10945 pts: intDts,
10946 cts: 0,
10947 unit: _silentUnit,
10948 size: _silentUnit.byteLength,
10949 duration: 0, // wait for next sample
10950 originalDts: originalDts,
10951 flags: {
10952 isLeading: 0,
10953 dependsOn: 1,
10954 isDependedOn: 0,
10955 hasRedundancy: 0
10956 }
10957 };
10958 silentFrames.push(frame);
10959 mdatBytes += frame.size;
10960 currentDts += refSampleDuration;
10961 }
10962
10963 // last frame: align end time to next frame dts
10964 var lastFrame = silentFrames[silentFrames.length - 1];
10965 lastFrame.duration = _dts + sampleDuration - lastFrame.dts;
10966
10967 // silentFrames.forEach((frame) => {
10968 // Log.w(this.TAG, `SilentAudio: dts: ${frame.dts}, duration: ${frame.duration}`);
10969 // });
10970
10971 // Set correct sample duration for current frame
10972 sampleDuration = Math.round(refSampleDuration);
10973 }
10974
10975 mp4Samples.push({
10976 dts: _dts,
10977 pts: _dts,
10978 cts: 0,
10979 unit: _sample.unit,
10980 size: _sample.unit.byteLength,
10981 duration: sampleDuration,
10982 originalDts: originalDts,
10983 flags: {
10984 isLeading: 0,
10985 dependsOn: 1,
10986 isDependedOn: 0,
10987 hasRedundancy: 0
10988 }
10989 });
10990
10991 if (needFillSilentFrames) {
10992 // Silent frames should be inserted after wrong-duration frame
10993 mp4Samples.push.apply(mp4Samples, silentFrames);
10994 }
10995 }
10996
10997 // allocate mdatbox
10998 if (mpegRawTrack) {
10999 // allocate for raw mpeg buffer
11000 mdatbox = new Uint8Array(mdatBytes);
11001 } else {
11002 // allocate for fmp4 mdat box
11003 mdatbox = new Uint8Array(mdatBytes);
11004 // size field
11005 mdatbox[0] = mdatBytes >>> 24 & 0xFF;
11006 mdatbox[1] = mdatBytes >>> 16 & 0xFF;
11007 mdatbox[2] = mdatBytes >>> 8 & 0xFF;
11008 mdatbox[3] = mdatBytes & 0xFF;
11009 // type field (fourCC)
11010 mdatbox.set(_mp4Generator2.default.types.mdat, 4);
11011 }
11012
11013 // Write samples into mdatbox
11014 for (var _i = 0; _i < mp4Samples.length; _i++) {
11015 var _unit = mp4Samples[_i].unit;
11016 mdatbox.set(_unit, offset);
11017 offset += _unit.byteLength;
11018 }
11019
11020 var latest = mp4Samples[mp4Samples.length - 1];
11021 lastDts = latest.dts + latest.duration;
11022 this._audioNextDts = lastDts;
11023
11024 // fill media segment info & add to info list
11025 var info = new _mediaSegmentInfo.MediaSegmentInfo();
11026 info.beginDts = firstDts;
11027 info.endDts = lastDts;
11028 info.beginPts = firstDts;
11029 info.endPts = lastDts;
11030 info.originalBeginDts = mp4Samples[0].originalDts;
11031 info.originalEndDts = latest.originalDts + latest.duration;
11032 info.firstSample = new _mediaSegmentInfo.SampleInfo(mp4Samples[0].dts, mp4Samples[0].pts, mp4Samples[0].duration, mp4Samples[0].originalDts, false);
11033 info.lastSample = new _mediaSegmentInfo.SampleInfo(latest.dts, latest.pts, latest.duration, latest.originalDts, false);
11034 if (!this._isLive) {
11035 this._audioSegmentInfoList.append(info);
11036 }
11037
11038 track.samples = mp4Samples;
11039 track.sequenceNumber++;
11040
11041 var moofbox = null;
11042
11043 if (mpegRawTrack) {
11044 // Generate empty buffer, because useless for raw mpeg
11045 moofbox = new Uint8Array();
11046 } else {
11047 // Generate moof for fmp4 segment
11048 moofbox = _mp4Generator2.default.moof(track, firstDts);
11049 }
11050
11051 track.samples = [];
11052 track.length = 0;
11053
11054 var segment = {
11055 type: 'audio',
11056 data: this._mergeBoxes(moofbox, mdatbox).buffer,
11057 sampleCount: mp4Samples.length,
11058 info: info
11059 };
11060
11061 if (mpegRawTrack && firstSegmentAfterSeek) {
11062 // For MPEG audio stream in MSE, if seeking occurred, before appending new buffer
11063 // We need explicitly set timestampOffset to the desired point in timeline for mpeg SourceBuffer.
11064 segment.timestampOffset = firstDts;
11065 }
11066
11067 this._onMediaSegment('audio', segment);
11068 }
11069 }, {
11070 key: '_remuxVideo',
11071 value: function _remuxVideo(videoTrack, force) {
11072 if (this._videoMeta == null) {
11073 return;
11074 }
11075
11076 var track = videoTrack;
11077 var samples = track.samples;
11078 var dtsCorrection = undefined;
11079 var firstDts = -1,
11080 lastDts = -1;
11081 var firstPts = -1,
11082 lastPts = -1;
11083
11084 if (!samples || samples.length === 0) {
11085 return;
11086 }
11087 if (samples.length === 1 && !force) {
11088 // If [sample count in current batch] === 1 && (force != true)
11089 // Ignore and keep in demuxer's queue
11090 return;
11091 } // else if (force === true) do remux
11092
11093 var offset = 8;
11094 var mdatbox = null;
11095 var mdatBytes = 8 + videoTrack.length;
11096
11097 var lastSample = null;
11098
11099 // Pop the lastSample and waiting for stash
11100 if (samples.length > 1) {
11101 lastSample = samples.pop();
11102 mdatBytes -= lastSample.length;
11103 }
11104
11105 // Insert [stashed lastSample in the previous batch] to the front
11106 if (this._videoStashedLastSample != null) {
11107 var sample = this._videoStashedLastSample;
11108 this._videoStashedLastSample = null;
11109 samples.unshift(sample);
11110 mdatBytes += sample.length;
11111 }
11112
11113 // Stash the lastSample of current batch, waiting for next batch
11114 if (lastSample != null) {
11115 this._videoStashedLastSample = lastSample;
11116 }
11117
11118 var firstSampleOriginalDts = samples[0].dts - this._dtsBase;
11119
11120 // calculate dtsCorrection
11121 if (this._videoNextDts) {
11122 dtsCorrection = firstSampleOriginalDts - this._videoNextDts;
11123 } else {
11124 // this._videoNextDts == undefined
11125 if (this._videoSegmentInfoList.isEmpty()) {
11126 dtsCorrection = 0;
11127 } else {
11128 var _lastSample2 = this._videoSegmentInfoList.getLastSampleBefore(firstSampleOriginalDts);
11129 if (_lastSample2 != null) {
11130 var distance = firstSampleOriginalDts - (_lastSample2.originalDts + _lastSample2.duration);
11131 if (distance <= 3) {
11132 distance = 0;
11133 }
11134 var expectedDts = _lastSample2.dts + _lastSample2.duration + distance;
11135 dtsCorrection = firstSampleOriginalDts - expectedDts;
11136 } else {
11137 // lastSample == null, cannot found
11138 dtsCorrection = 0;
11139 }
11140 }
11141 }
11142
11143 var info = new _mediaSegmentInfo.MediaSegmentInfo();
11144 var mp4Samples = [];
11145
11146 // Correct dts for each sample, and calculate sample duration. Then output to mp4Samples
11147 for (var i = 0; i < samples.length; i++) {
11148 var _sample2 = samples[i];
11149 var originalDts = _sample2.dts - this._dtsBase;
11150 var isKeyframe = _sample2.isKeyframe;
11151 var dts = originalDts - dtsCorrection;
11152 var cts = _sample2.cts;
11153 var pts = dts + cts;
11154
11155 if (firstDts === -1) {
11156 firstDts = dts;
11157 firstPts = pts;
11158 }
11159
11160 var sampleDuration = 0;
11161
11162 if (i !== samples.length - 1) {
11163 var nextDts = samples[i + 1].dts - this._dtsBase - dtsCorrection;
11164 sampleDuration = nextDts - dts;
11165 } else {
11166 // the last sample
11167 if (lastSample != null) {
11168 // use stashed sample's dts to calculate sample duration
11169 var _nextDts2 = lastSample.dts - this._dtsBase - dtsCorrection;
11170 sampleDuration = _nextDts2 - dts;
11171 } else if (mp4Samples.length >= 1) {
11172 // use second last sample duration
11173 sampleDuration = mp4Samples[mp4Samples.length - 1].duration;
11174 } else {
11175 // the only one sample, use reference sample duration
11176 sampleDuration = Math.floor(this._videoMeta.refSampleDuration);
11177 }
11178 }
11179
11180 if (isKeyframe) {
11181 var syncPoint = new _mediaSegmentInfo.SampleInfo(dts, pts, sampleDuration, _sample2.dts, true);
11182 syncPoint.fileposition = _sample2.fileposition;
11183 info.appendSyncPoint(syncPoint);
11184 }
11185
11186 mp4Samples.push({
11187 dts: dts,
11188 pts: pts,
11189 cts: cts,
11190 units: _sample2.units,
11191 size: _sample2.length,
11192 isKeyframe: isKeyframe,
11193 duration: sampleDuration,
11194 originalDts: originalDts,
11195 flags: {
11196 isLeading: 0,
11197 dependsOn: isKeyframe ? 2 : 1,
11198 isDependedOn: isKeyframe ? 1 : 0,
11199 hasRedundancy: 0,
11200 isNonSync: isKeyframe ? 0 : 1
11201 }
11202 });
11203 }
11204
11205 // allocate mdatbox
11206 mdatbox = new Uint8Array(mdatBytes);
11207 mdatbox[0] = mdatBytes >>> 24 & 0xFF;
11208 mdatbox[1] = mdatBytes >>> 16 & 0xFF;
11209 mdatbox[2] = mdatBytes >>> 8 & 0xFF;
11210 mdatbox[3] = mdatBytes & 0xFF;
11211 mdatbox.set(_mp4Generator2.default.types.mdat, 4);
11212
11213 // Write samples into mdatbox
11214 for (var _i2 = 0; _i2 < mp4Samples.length; _i2++) {
11215 var units = mp4Samples[_i2].units;
11216 while (units.length) {
11217 var unit = units.shift();
11218 var data = unit.data;
11219 mdatbox.set(data, offset);
11220 offset += data.byteLength;
11221 }
11222 }
11223
11224 var latest = mp4Samples[mp4Samples.length - 1];
11225 lastDts = latest.dts + latest.duration;
11226 lastPts = latest.pts + latest.duration;
11227 this._videoNextDts = lastDts;
11228
11229 // fill media segment info & add to info list
11230 info.beginDts = firstDts;
11231 info.endDts = lastDts;
11232 info.beginPts = firstPts;
11233 info.endPts = lastPts;
11234 info.originalBeginDts = mp4Samples[0].originalDts;
11235 info.originalEndDts = latest.originalDts + latest.duration;
11236 info.firstSample = new _mediaSegmentInfo.SampleInfo(mp4Samples[0].dts, mp4Samples[0].pts, mp4Samples[0].duration, mp4Samples[0].originalDts, mp4Samples[0].isKeyframe);
11237 info.lastSample = new _mediaSegmentInfo.SampleInfo(latest.dts, latest.pts, latest.duration, latest.originalDts, latest.isKeyframe);
11238 if (!this._isLive) {
11239 this._videoSegmentInfoList.append(info);
11240 }
11241
11242 track.samples = mp4Samples;
11243 track.sequenceNumber++;
11244
11245 // workaround for chrome < 50: force first sample as a random access point
11246 // see https://bugs.chromium.org/p/chromium/issues/detail?id=229412
11247 if (this._forceFirstIDR) {
11248 var flags = mp4Samples[0].flags;
11249 flags.dependsOn = 2;
11250 flags.isNonSync = 0;
11251 }
11252
11253 var moofbox = _mp4Generator2.default.moof(track, firstDts);
11254 track.samples = [];
11255 track.length = 0;
11256
11257 this._onMediaSegment('video', {
11258 type: 'video',
11259 data: this._mergeBoxes(moofbox, mdatbox).buffer,
11260 sampleCount: mp4Samples.length,
11261 info: info
11262 });
11263 }
11264 }, {
11265 key: '_mergeBoxes',
11266 value: function _mergeBoxes(moof, mdat) {
11267 var result = new Uint8Array(moof.byteLength + mdat.byteLength);
11268 result.set(moof, 0);
11269 result.set(mdat, moof.byteLength);
11270 return result;
11271 }
11272 }, {
11273 key: 'onInitSegment',
11274 get: function get() {
11275 return this._onInitSegment;
11276 },
11277 set: function set(callback) {
11278 this._onInitSegment = callback;
11279 }
11280
11281 /* prototype: function onMediaSegment(type: string, mediaSegment: MediaSegment): void
11282 MediaSegment: {
11283 type: string,
11284 data: ArrayBuffer,
11285 sampleCount: int32
11286 info: MediaSegmentInfo
11287 }
11288 */
11289
11290 }, {
11291 key: 'onMediaSegment',
11292 get: function get() {
11293 return this._onMediaSegment;
11294 },
11295 set: function set(callback) {
11296 this._onMediaSegment = callback;
11297 }
11298 }]);
11299
11300 return MP4Remuxer;
11301}();
11302
11303exports.default = MP4Remuxer;
11304
11305},{"../core/media-segment-info.js":8,"../utils/browser.js":39,"../utils/exception.js":40,"../utils/logger.js":41,"./aac-silent.js":36,"./mp4-generator.js":37}],39:[function(_dereq_,module,exports){
11306'use strict';
11307
11308Object.defineProperty(exports, "__esModule", {
11309 value: true
11310});
11311/*
11312 * Copyright (C) 2016 Bilibili. All Rights Reserved.
11313 *
11314 * @author zheng qian <xqq@xqq.im>
11315 *
11316 * Licensed under the Apache License, Version 2.0 (the "License");
11317 * you may not use this file except in compliance with the License.
11318 * You may obtain a copy of the License at
11319 *
11320 * http://www.apache.org/licenses/LICENSE-2.0
11321 *
11322 * Unless required by applicable law or agreed to in writing, software
11323 * distributed under the License is distributed on an "AS IS" BASIS,
11324 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11325 * See the License for the specific language governing permissions and
11326 * limitations under the License.
11327 */
11328
11329var Browser = {};
11330
11331function detect() {
11332 // modified from jquery-browser-plugin
11333
11334 var ua = self.navigator.userAgent.toLowerCase();
11335
11336 var match = /(edge)\/([\w.]+)/.exec(ua) || /(opr)[\/]([\w.]+)/.exec(ua) || /(chrome)[ \/]([\w.]+)/.exec(ua) || /(iemobile)[\/]([\w.]+)/.exec(ua) || /(version)(applewebkit)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+).*(version)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+)/.exec(ua) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf('trident') >= 0 && /(rv)(?::| )([\w.]+)/.exec(ua) || ua.indexOf('compatible') < 0 && /(firefox)[ \/]([\w.]+)/.exec(ua) || [];
11337
11338 var platform_match = /(ipad)/.exec(ua) || /(ipod)/.exec(ua) || /(windows phone)/.exec(ua) || /(iphone)/.exec(ua) || /(kindle)/.exec(ua) || /(android)/.exec(ua) || /(windows)/.exec(ua) || /(mac)/.exec(ua) || /(linux)/.exec(ua) || /(cros)/.exec(ua) || [];
11339
11340 var matched = {
11341 browser: match[5] || match[3] || match[1] || '',
11342 version: match[2] || match[4] || '0',
11343 majorVersion: match[4] || match[2] || '0',
11344 platform: platform_match[0] || ''
11345 };
11346
11347 var browser = {};
11348 if (matched.browser) {
11349 browser[matched.browser] = true;
11350
11351 var versionArray = matched.majorVersion.split('.');
11352 browser.version = {
11353 major: parseInt(matched.majorVersion, 10),
11354 string: matched.version
11355 };
11356 if (versionArray.length > 1) {
11357 browser.version.minor = parseInt(versionArray[1], 10);
11358 }
11359 if (versionArray.length > 2) {
11360 browser.version.build = parseInt(versionArray[2], 10);
11361 }
11362 }
11363
11364 if (matched.platform) {
11365 browser[matched.platform] = true;
11366 }
11367
11368 if (browser.chrome || browser.opr || browser.safari) {
11369 browser.webkit = true;
11370 }
11371
11372 // MSIE. IE11 has 'rv' identifer
11373 if (browser.rv || browser.iemobile) {
11374 if (browser.rv) {
11375 delete browser.rv;
11376 }
11377 var msie = 'msie';
11378 matched.browser = msie;
11379 browser[msie] = true;
11380 }
11381
11382 // Microsoft Edge
11383 if (browser.edge) {
11384 delete browser.edge;
11385 var msedge = 'msedge';
11386 matched.browser = msedge;
11387 browser[msedge] = true;
11388 }
11389
11390 // Opera 15+
11391 if (browser.opr) {
11392 var opera = 'opera';
11393 matched.browser = opera;
11394 browser[opera] = true;
11395 }
11396
11397 // Stock android browsers are marked as Safari
11398 if (browser.safari && browser.android) {
11399 var android = 'android';
11400 matched.browser = android;
11401 browser[android] = true;
11402 }
11403
11404 browser.name = matched.browser;
11405 browser.platform = matched.platform;
11406
11407 for (var key in Browser) {
11408 if (Browser.hasOwnProperty(key)) {
11409 delete Browser[key];
11410 }
11411 }
11412 Object.assign(Browser, browser);
11413}
11414
11415detect();
11416
11417exports.default = Browser;
11418
11419},{}],40:[function(_dereq_,module,exports){
11420'use strict';
11421
11422Object.defineProperty(exports, "__esModule", {
11423 value: true
11424});
11425
11426var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
11427
11428function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
11429
11430function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
11431
11432function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
11433
11434/*
11435 * Copyright (C) 2016 Bilibili. All Rights Reserved.
11436 *
11437 * @author zheng qian <xqq@xqq.im>
11438 *
11439 * Licensed under the Apache License, Version 2.0 (the "License");
11440 * you may not use this file except in compliance with the License.
11441 * You may obtain a copy of the License at
11442 *
11443 * http://www.apache.org/licenses/LICENSE-2.0
11444 *
11445 * Unless required by applicable law or agreed to in writing, software
11446 * distributed under the License is distributed on an "AS IS" BASIS,
11447 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11448 * See the License for the specific language governing permissions and
11449 * limitations under the License.
11450 */
11451
11452var RuntimeException = exports.RuntimeException = function () {
11453 function RuntimeException(message) {
11454 _classCallCheck(this, RuntimeException);
11455
11456 this._message = message;
11457 }
11458
11459 _createClass(RuntimeException, [{
11460 key: 'toString',
11461 value: function toString() {
11462 return this.name + ': ' + this.message;
11463 }
11464 }, {
11465 key: 'name',
11466 get: function get() {
11467 return 'RuntimeException';
11468 }
11469 }, {
11470 key: 'message',
11471 get: function get() {
11472 return this._message;
11473 }
11474 }]);
11475
11476 return RuntimeException;
11477}();
11478
11479var IllegalStateException = exports.IllegalStateException = function (_RuntimeException) {
11480 _inherits(IllegalStateException, _RuntimeException);
11481
11482 function IllegalStateException(message) {
11483 _classCallCheck(this, IllegalStateException);
11484
11485 return _possibleConstructorReturn(this, (IllegalStateException.__proto__ || Object.getPrototypeOf(IllegalStateException)).call(this, message));
11486 }
11487
11488 _createClass(IllegalStateException, [{
11489 key: 'name',
11490 get: function get() {
11491 return 'IllegalStateException';
11492 }
11493 }]);
11494
11495 return IllegalStateException;
11496}(RuntimeException);
11497
11498var InvalidArgumentException = exports.InvalidArgumentException = function (_RuntimeException2) {
11499 _inherits(InvalidArgumentException, _RuntimeException2);
11500
11501 function InvalidArgumentException(message) {
11502 _classCallCheck(this, InvalidArgumentException);
11503
11504 return _possibleConstructorReturn(this, (InvalidArgumentException.__proto__ || Object.getPrototypeOf(InvalidArgumentException)).call(this, message));
11505 }
11506
11507 _createClass(InvalidArgumentException, [{
11508 key: 'name',
11509 get: function get() {
11510 return 'InvalidArgumentException';
11511 }
11512 }]);
11513
11514 return InvalidArgumentException;
11515}(RuntimeException);
11516
11517var NotImplementedException = exports.NotImplementedException = function (_RuntimeException3) {
11518 _inherits(NotImplementedException, _RuntimeException3);
11519
11520 function NotImplementedException(message) {
11521 _classCallCheck(this, NotImplementedException);
11522
11523 return _possibleConstructorReturn(this, (NotImplementedException.__proto__ || Object.getPrototypeOf(NotImplementedException)).call(this, message));
11524 }
11525
11526 _createClass(NotImplementedException, [{
11527 key: 'name',
11528 get: function get() {
11529 return 'NotImplementedException';
11530 }
11531 }]);
11532
11533 return NotImplementedException;
11534}(RuntimeException);
11535
11536},{}],41:[function(_dereq_,module,exports){
11537'use strict';
11538
11539Object.defineProperty(exports, "__esModule", {
11540 value: true
11541});
11542
11543var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
11544 * Copyright (C) 2016 Bilibili. All Rights Reserved.
11545 *
11546 * @author zheng qian <xqq@xqq.im>
11547 *
11548 * Licensed under the Apache License, Version 2.0 (the "License");
11549 * you may not use this file except in compliance with the License.
11550 * You may obtain a copy of the License at
11551 *
11552 * http://www.apache.org/licenses/LICENSE-2.0
11553 *
11554 * Unless required by applicable law or agreed to in writing, software
11555 * distributed under the License is distributed on an "AS IS" BASIS,
11556 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11557 * See the License for the specific language governing permissions and
11558 * limitations under the License.
11559 */
11560
11561var _events = _dereq_('events');
11562
11563var _events2 = _interopRequireDefault(_events);
11564
11565function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11566
11567function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
11568
11569var Log = function () {
11570 function Log() {
11571 _classCallCheck(this, Log);
11572 }
11573
11574 _createClass(Log, null, [{
11575 key: 'e',
11576 value: function e(tag, msg) {
11577 if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
11578
11579 var str = '[' + tag + '] > ' + msg;
11580
11581 if (Log.ENABLE_CALLBACK) {
11582 Log.emitter.emit('log', 'error', str);
11583 }
11584
11585 if (!Log.ENABLE_ERROR) {
11586 return;
11587 }
11588
11589 if (console.error) {
11590 console.error(str);
11591 } else if (console.warn) {
11592 console.warn(str);
11593 } else {
11594 console.log(str);
11595 }
11596 }
11597 }, {
11598 key: 'i',
11599 value: function i(tag, msg) {
11600 if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
11601
11602 var str = '[' + tag + '] > ' + msg;
11603
11604 if (Log.ENABLE_CALLBACK) {
11605 Log.emitter.emit('log', 'info', str);
11606 }
11607
11608 if (!Log.ENABLE_INFO) {
11609 return;
11610 }
11611
11612 if (console.info) {
11613 console.info(str);
11614 } else {
11615 console.log(str);
11616 }
11617 }
11618 }, {
11619 key: 'w',
11620 value: function w(tag, msg) {
11621 if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
11622
11623 var str = '[' + tag + '] > ' + msg;
11624
11625 if (Log.ENABLE_CALLBACK) {
11626 Log.emitter.emit('log', 'warn', str);
11627 }
11628
11629 if (!Log.ENABLE_WARN) {
11630 return;
11631 }
11632
11633 if (console.warn) {
11634 console.warn(str);
11635 } else {
11636 console.log(str);
11637 }
11638 }
11639 }, {
11640 key: 'd',
11641 value: function d(tag, msg) {
11642 if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
11643
11644 var str = '[' + tag + '] > ' + msg;
11645
11646 if (Log.ENABLE_CALLBACK) {
11647 Log.emitter.emit('log', 'debug', str);
11648 }
11649
11650 if (!Log.ENABLE_DEBUG) {
11651 return;
11652 }
11653
11654 if (console.debug) {
11655 console.debug(str);
11656 } else {
11657 console.log(str);
11658 }
11659 }
11660 }, {
11661 key: 'v',
11662 value: function v(tag, msg) {
11663 if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
11664
11665 var str = '[' + tag + '] > ' + msg;
11666
11667 if (Log.ENABLE_CALLBACK) {
11668 Log.emitter.emit('log', 'verbose', str);
11669 }
11670
11671 if (!Log.ENABLE_VERBOSE) {
11672 return;
11673 }
11674
11675 console.log(str);
11676 }
11677 }]);
11678
11679 return Log;
11680}();
11681
11682Log.GLOBAL_TAG = 'flv.js';
11683Log.FORCE_GLOBAL_TAG = false;
11684Log.ENABLE_ERROR = true;
11685Log.ENABLE_INFO = true;
11686Log.ENABLE_WARN = true;
11687Log.ENABLE_DEBUG = true;
11688Log.ENABLE_VERBOSE = true;
11689
11690Log.ENABLE_CALLBACK = false;
11691
11692Log.emitter = new _events2.default();
11693
11694exports.default = Log;
11695
11696},{"events":2}],42:[function(_dereq_,module,exports){
11697'use strict';
11698
11699Object.defineProperty(exports, "__esModule", {
11700 value: true
11701});
11702
11703var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
11704 * Copyright (C) 2016 Bilibili. All Rights Reserved.
11705 *
11706 * @author zheng qian <xqq@xqq.im>
11707 *
11708 * Licensed under the Apache License, Version 2.0 (the "License");
11709 * you may not use this file except in compliance with the License.
11710 * You may obtain a copy of the License at
11711 *
11712 * http://www.apache.org/licenses/LICENSE-2.0
11713 *
11714 * Unless required by applicable law or agreed to in writing, software
11715 * distributed under the License is distributed on an "AS IS" BASIS,
11716 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11717 * See the License for the specific language governing permissions and
11718 * limitations under the License.
11719 */
11720
11721var _events = _dereq_('events');
11722
11723var _events2 = _interopRequireDefault(_events);
11724
11725var _logger = _dereq_('./logger.js');
11726
11727var _logger2 = _interopRequireDefault(_logger);
11728
11729function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11730
11731function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
11732
11733var LoggingControl = function () {
11734 function LoggingControl() {
11735 _classCallCheck(this, LoggingControl);
11736 }
11737
11738 _createClass(LoggingControl, null, [{
11739 key: 'getConfig',
11740 value: function getConfig() {
11741 return {
11742 globalTag: _logger2.default.GLOBAL_TAG,
11743 forceGlobalTag: _logger2.default.FORCE_GLOBAL_TAG,
11744 enableVerbose: _logger2.default.ENABLE_VERBOSE,
11745 enableDebug: _logger2.default.ENABLE_DEBUG,
11746 enableInfo: _logger2.default.ENABLE_INFO,
11747 enableWarn: _logger2.default.ENABLE_WARN,
11748 enableError: _logger2.default.ENABLE_ERROR,
11749 enableCallback: _logger2.default.ENABLE_CALLBACK
11750 };
11751 }
11752 }, {
11753 key: 'applyConfig',
11754 value: function applyConfig(config) {
11755 _logger2.default.GLOBAL_TAG = config.globalTag;
11756 _logger2.default.FORCE_GLOBAL_TAG = config.forceGlobalTag;
11757 _logger2.default.ENABLE_VERBOSE = config.enableVerbose;
11758 _logger2.default.ENABLE_DEBUG = config.enableDebug;
11759 _logger2.default.ENABLE_INFO = config.enableInfo;
11760 _logger2.default.ENABLE_WARN = config.enableWarn;
11761 _logger2.default.ENABLE_ERROR = config.enableError;
11762 _logger2.default.ENABLE_CALLBACK = config.enableCallback;
11763 }
11764 }, {
11765 key: '_notifyChange',
11766 value: function _notifyChange() {
11767 var emitter = LoggingControl.emitter;
11768
11769 if (emitter.listenerCount('change') > 0) {
11770 var config = LoggingControl.getConfig();
11771 emitter.emit('change', config);
11772 }
11773 }
11774 }, {
11775 key: 'registerListener',
11776 value: function registerListener(listener) {
11777 LoggingControl.emitter.addListener('change', listener);
11778 }
11779 }, {
11780 key: 'removeListener',
11781 value: function removeListener(listener) {
11782 LoggingControl.emitter.removeListener('change', listener);
11783 }
11784 }, {
11785 key: 'addLogListener',
11786 value: function addLogListener(listener) {
11787 _logger2.default.emitter.addListener('log', listener);
11788 if (_logger2.default.emitter.listenerCount('log') > 0) {
11789 _logger2.default.ENABLE_CALLBACK = true;
11790 LoggingControl._notifyChange();
11791 }
11792 }
11793 }, {
11794 key: 'removeLogListener',
11795 value: function removeLogListener(listener) {
11796 _logger2.default.emitter.removeListener('log', listener);
11797 if (_logger2.default.emitter.listenerCount('log') === 0) {
11798 _logger2.default.ENABLE_CALLBACK = false;
11799 LoggingControl._notifyChange();
11800 }
11801 }
11802 }, {
11803 key: 'forceGlobalTag',
11804 get: function get() {
11805 return _logger2.default.FORCE_GLOBAL_TAG;
11806 },
11807 set: function set(enable) {
11808 _logger2.default.FORCE_GLOBAL_TAG = enable;
11809 LoggingControl._notifyChange();
11810 }
11811 }, {
11812 key: 'globalTag',
11813 get: function get() {
11814 return _logger2.default.GLOBAL_TAG;
11815 },
11816 set: function set(tag) {
11817 _logger2.default.GLOBAL_TAG = tag;
11818 LoggingControl._notifyChange();
11819 }
11820 }, {
11821 key: 'enableAll',
11822 get: function get() {
11823 return _logger2.default.ENABLE_VERBOSE && _logger2.default.ENABLE_DEBUG && _logger2.default.ENABLE_INFO && _logger2.default.ENABLE_WARN && _logger2.default.ENABLE_ERROR;
11824 },
11825 set: function set(enable) {
11826 _logger2.default.ENABLE_VERBOSE = enable;
11827 _logger2.default.ENABLE_DEBUG = enable;
11828 _logger2.default.ENABLE_INFO = enable;
11829 _logger2.default.ENABLE_WARN = enable;
11830 _logger2.default.ENABLE_ERROR = enable;
11831 LoggingControl._notifyChange();
11832 }
11833 }, {
11834 key: 'enableDebug',
11835 get: function get() {
11836 return _logger2.default.ENABLE_DEBUG;
11837 },
11838 set: function set(enable) {
11839 _logger2.default.ENABLE_DEBUG = enable;
11840 LoggingControl._notifyChange();
11841 }
11842 }, {
11843 key: 'enableVerbose',
11844 get: function get() {
11845 return _logger2.default.ENABLE_VERBOSE;
11846 },
11847 set: function set(enable) {
11848 _logger2.default.ENABLE_VERBOSE = enable;
11849 LoggingControl._notifyChange();
11850 }
11851 }, {
11852 key: 'enableInfo',
11853 get: function get() {
11854 return _logger2.default.ENABLE_INFO;
11855 },
11856 set: function set(enable) {
11857 _logger2.default.ENABLE_INFO = enable;
11858 LoggingControl._notifyChange();
11859 }
11860 }, {
11861 key: 'enableWarn',
11862 get: function get() {
11863 return _logger2.default.ENABLE_WARN;
11864 },
11865 set: function set(enable) {
11866 _logger2.default.ENABLE_WARN = enable;
11867 LoggingControl._notifyChange();
11868 }
11869 }, {
11870 key: 'enableError',
11871 get: function get() {
11872 return _logger2.default.ENABLE_ERROR;
11873 },
11874 set: function set(enable) {
11875 _logger2.default.ENABLE_ERROR = enable;
11876 LoggingControl._notifyChange();
11877 }
11878 }]);
11879
11880 return LoggingControl;
11881}();
11882
11883LoggingControl.emitter = new _events2.default();
11884
11885exports.default = LoggingControl;
11886
11887},{"./logger.js":41,"events":2}],43:[function(_dereq_,module,exports){
11888'use strict';
11889
11890Object.defineProperty(exports, "__esModule", {
11891 value: true
11892});
11893
11894var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
11895
11896function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
11897
11898/*
11899 * Copyright (C) 2016 Bilibili. All Rights Reserved.
11900 *
11901 * @author zheng qian <xqq@xqq.im>
11902 *
11903 * Licensed under the Apache License, Version 2.0 (the "License");
11904 * you may not use this file except in compliance with the License.
11905 * You may obtain a copy of the License at
11906 *
11907 * http://www.apache.org/licenses/LICENSE-2.0
11908 *
11909 * Unless required by applicable law or agreed to in writing, software
11910 * distributed under the License is distributed on an "AS IS" BASIS,
11911 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11912 * See the License for the specific language governing permissions and
11913 * limitations under the License.
11914 */
11915
11916var Polyfill = function () {
11917 function Polyfill() {
11918 _classCallCheck(this, Polyfill);
11919 }
11920
11921 _createClass(Polyfill, null, [{
11922 key: 'install',
11923 value: function install() {
11924 // ES6 Object.setPrototypeOf
11925 Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
11926 obj.__proto__ = proto;
11927 return obj;
11928 };
11929
11930 // ES6 Object.assign
11931 Object.assign = Object.assign || function (target) {
11932 if (target === undefined || target === null) {
11933 throw new TypeError('Cannot convert undefined or null to object');
11934 }
11935
11936 var output = Object(target);
11937 for (var i = 1; i < arguments.length; i++) {
11938 var source = arguments[i];
11939 if (source !== undefined && source !== null) {
11940 for (var key in source) {
11941 if (source.hasOwnProperty(key)) {
11942 output[key] = source[key];
11943 }
11944 }
11945 }
11946 }
11947 return output;
11948 };
11949
11950 // ES6 Promise (missing support in IE11)
11951 if (typeof self.Promise !== 'function') {
11952 _dereq_('es6-promise').polyfill();
11953 }
11954 }
11955 }]);
11956
11957 return Polyfill;
11958}();
11959
11960Polyfill.install();
11961
11962exports.default = Polyfill;
11963
11964},{"es6-promise":1}],44:[function(_dereq_,module,exports){
11965'use strict';
11966
11967Object.defineProperty(exports, "__esModule", {
11968 value: true
11969});
11970/*
11971 * Copyright (C) 2016 Bilibili. All Rights Reserved.
11972 *
11973 * This file is derived from C++ project libWinTF8 (https://github.com/m13253/libWinTF8)
11974 * @author zheng qian <xqq@xqq.im>
11975 *
11976 * Licensed under the Apache License, Version 2.0 (the "License");
11977 * you may not use this file except in compliance with the License.
11978 * You may obtain a copy of the License at
11979 *
11980 * http://www.apache.org/licenses/LICENSE-2.0
11981 *
11982 * Unless required by applicable law or agreed to in writing, software
11983 * distributed under the License is distributed on an "AS IS" BASIS,
11984 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11985 * See the License for the specific language governing permissions and
11986 * limitations under the License.
11987 */
11988
11989function checkContinuation(uint8array, start, checkLength) {
11990 var array = uint8array;
11991 if (start + checkLength < array.length) {
11992 while (checkLength--) {
11993 if ((array[++start] & 0xC0) !== 0x80) return false;
11994 }
11995 return true;
11996 } else {
11997 return false;
11998 }
11999}
12000
12001function decodeUTF8(uint8array) {
12002 var out = [];
12003 var input = uint8array;
12004 var i = 0;
12005 var length = uint8array.length;
12006
12007 while (i < length) {
12008 if (input[i] < 0x80) {
12009 out.push(String.fromCharCode(input[i]));
12010 ++i;
12011 continue;
12012 } else if (input[i] < 0xC0) {
12013 // fallthrough
12014 } else if (input[i] < 0xE0) {
12015 if (checkContinuation(input, i, 1)) {
12016 var ucs4 = (input[i] & 0x1F) << 6 | input[i + 1] & 0x3F;
12017 if (ucs4 >= 0x80) {
12018 out.push(String.fromCharCode(ucs4 & 0xFFFF));
12019 i += 2;
12020 continue;
12021 }
12022 }
12023 } else if (input[i] < 0xF0) {
12024 if (checkContinuation(input, i, 2)) {
12025 var _ucs = (input[i] & 0xF) << 12 | (input[i + 1] & 0x3F) << 6 | input[i + 2] & 0x3F;
12026 if (_ucs >= 0x800 && (_ucs & 0xF800) !== 0xD800) {
12027 out.push(String.fromCharCode(_ucs & 0xFFFF));
12028 i += 3;
12029 continue;
12030 }
12031 }
12032 } else if (input[i] < 0xF8) {
12033 if (checkContinuation(input, i, 3)) {
12034 var _ucs2 = (input[i] & 0x7) << 18 | (input[i + 1] & 0x3F) << 12 | (input[i + 2] & 0x3F) << 6 | input[i + 3] & 0x3F;
12035 if (_ucs2 > 0x10000 && _ucs2 < 0x110000) {
12036 _ucs2 -= 0x10000;
12037 out.push(String.fromCharCode(_ucs2 >>> 10 | 0xD800));
12038 out.push(String.fromCharCode(_ucs2 & 0x3FF | 0xDC00));
12039 i += 4;
12040 continue;
12041 }
12042 }
12043 }
12044 out.push(String.fromCharCode(0xFFFD));
12045 ++i;
12046 }
12047
12048 return out.join('');
12049}
12050
12051exports.default = decodeUTF8;
12052
12053},{}]},{},[21])(21)
12054});
12055
12056//# sourceMappingURL=flv.js.map