From 25ce610f6ecca7325e7a743dc032c4a76559c63d Mon Sep 17 00:00:00 2001
From: liuyg <376836862@qq.com>
Date: Fri, 02 Jul 2021 09:10:26 +0800
Subject: [PATCH] Merge branch 'master' of http://192.168.0.105:10010/r/pyhmap

---
 libs/flv/flvjs/flv.js | 23012 +++++++++++++++++++++++++++++-----------------------------
 1 files changed, 11,516 insertions(+), 11,496 deletions(-)

diff --git a/libs/flv/flvjs/flv.js b/libs/flv/flvjs/flv.js
index b76b91f..0d01221 100644
--- a/libs/flv/flvjs/flv.js
+++ b/libs/flv/flvjs/flv.js
@@ -1,4047 +1,4058 @@
-(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){
-(function (process,global){
-/*!
- * @overview es6-promise - a tiny implementation of Promises/A+.
- * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
- * @license   Licensed under MIT license
- *            See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
- * @version   v4.2.5+7f2b526d
- */
+(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) {
+            (function (process, global) {
+                /*!
+                 * @overview es6-promise - a tiny implementation of Promises/A+.
+                 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
+                 * @license   Licensed under MIT license
+                 *            See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
+                 * @version   v4.2.5+7f2b526d
+                 */
 
-(function (global, factory) {
-	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
-	typeof define === 'function' && define.amd ? define(factory) :
-	(global.ES6Promise = factory());
-}(this, (function () { 'use strict';
+                (function (global, factory) {
+                    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+                        typeof define === 'function' && define.amd ? define(factory) :
+                            (global.ES6Promise = factory());
+                }(this, (function () {
+                    'use strict';
 
-function objectOrFunction(x) {
-  var type = typeof x;
-  return x !== null && (type === 'object' || type === 'function');
-}
+                    function objectOrFunction(x) {
+                        var type = typeof x;
+                        return x !== null && (type === 'object' || type === 'function');
+                    }
 
-function isFunction(x) {
-  return typeof x === 'function';
-}
+                    function isFunction(x) {
+                        return typeof x === 'function';
+                    }
 
 
 
-var _isArray = void 0;
-if (Array.isArray) {
-  _isArray = Array.isArray;
-} else {
-  _isArray = function (x) {
-    return Object.prototype.toString.call(x) === '[object Array]';
-  };
-}
+                    var _isArray = void 0;
+                    if (Array.isArray) {
+                        _isArray = Array.isArray;
+                    } else {
+                        _isArray = function (x) {
+                            return Object.prototype.toString.call(x) === '[object Array]';
+                        };
+                    }
 
-var isArray = _isArray;
+                    var isArray = _isArray;
 
-var len = 0;
-var vertxNext = void 0;
-var customSchedulerFn = void 0;
+                    var len = 0;
+                    var vertxNext = void 0;
+                    var customSchedulerFn = void 0;
 
-var asap = function asap(callback, arg) {
-  queue[len] = callback;
-  queue[len + 1] = arg;
-  len += 2;
-  if (len === 2) {
-    // If len is 2, that means that we need to schedule an async flush.
-    // If additional callbacks are queued before the queue is flushed, they
-    // will be processed by this flush that we are scheduling.
-    if (customSchedulerFn) {
-      customSchedulerFn(flush);
-    } else {
-      scheduleFlush();
-    }
-  }
-};
-
-function setScheduler(scheduleFn) {
-  customSchedulerFn = scheduleFn;
-}
-
-function setAsap(asapFn) {
-  asap = asapFn;
-}
-
-var browserWindow = typeof window !== 'undefined' ? window : undefined;
-var browserGlobal = browserWindow || {};
-var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
-var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
-
-// test for web worker but not in IE10
-var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
-
-// node
-function useNextTick() {
-  // node version 0.10.x displays a deprecation warning when nextTick is used recursively
-  // see https://github.com/cujojs/when/issues/410 for details
-  return function () {
-    return process.nextTick(flush);
-  };
-}
-
-// vertx
-function useVertxTimer() {
-  if (typeof vertxNext !== 'undefined') {
-    return function () {
-      vertxNext(flush);
-    };
-  }
-
-  return useSetTimeout();
-}
-
-function useMutationObserver() {
-  var iterations = 0;
-  var observer = new BrowserMutationObserver(flush);
-  var node = document.createTextNode('');
-  observer.observe(node, { characterData: true });
-
-  return function () {
-    node.data = iterations = ++iterations % 2;
-  };
-}
-
-// web worker
-function useMessageChannel() {
-  var channel = new MessageChannel();
-  channel.port1.onmessage = flush;
-  return function () {
-    return channel.port2.postMessage(0);
-  };
-}
-
-function useSetTimeout() {
-  // Store setTimeout reference so es6-promise will be unaffected by
-  // other code modifying setTimeout (like sinon.useFakeTimers())
-  var globalSetTimeout = setTimeout;
-  return function () {
-    return globalSetTimeout(flush, 1);
-  };
-}
-
-var queue = new Array(1000);
-function flush() {
-  for (var i = 0; i < len; i += 2) {
-    var callback = queue[i];
-    var arg = queue[i + 1];
-
-    callback(arg);
-
-    queue[i] = undefined;
-    queue[i + 1] = undefined;
-  }
-
-  len = 0;
-}
-
-function attemptVertx() {
-  try {
-    var vertx = Function('return this')().require('vertx');
-    vertxNext = vertx.runOnLoop || vertx.runOnContext;
-    return useVertxTimer();
-  } catch (e) {
-    return useSetTimeout();
-  }
-}
-
-var scheduleFlush = void 0;
-// Decide what async method to use to triggering processing of queued callbacks:
-if (isNode) {
-  scheduleFlush = useNextTick();
-} else if (BrowserMutationObserver) {
-  scheduleFlush = useMutationObserver();
-} else if (isWorker) {
-  scheduleFlush = useMessageChannel();
-} else if (browserWindow === undefined && typeof _dereq_ === 'function') {
-  scheduleFlush = attemptVertx();
-} else {
-  scheduleFlush = useSetTimeout();
-}
-
-function then(onFulfillment, onRejection) {
-  var parent = this;
-
-  var child = new this.constructor(noop);
-
-  if (child[PROMISE_ID] === undefined) {
-    makePromise(child);
-  }
-
-  var _state = parent._state;
-
-
-  if (_state) {
-    var callback = arguments[_state - 1];
-    asap(function () {
-      return invokeCallback(_state, child, callback, parent._result);
-    });
-  } else {
-    subscribe(parent, child, onFulfillment, onRejection);
-  }
-
-  return child;
-}
-
-/**
-  `Promise.resolve` returns a promise that will become resolved with the
-  passed `value`. It is shorthand for the following:
-
-  ```javascript
-  let promise = new Promise(function(resolve, reject){
-    resolve(1);
-  });
-
-  promise.then(function(value){
-    // value === 1
-  });
-  ```
-
-  Instead of writing the above, your code now simply becomes the following:
-
-  ```javascript
-  let promise = Promise.resolve(1);
-
-  promise.then(function(value){
-    // value === 1
-  });
-  ```
-
-  @method resolve
-  @static
-  @param {Any} value value that the returned promise will be resolved with
-  Useful for tooling.
-  @return {Promise} a promise that will become fulfilled with the given
-  `value`
-*/
-function resolve$1(object) {
-  /*jshint validthis:true */
-  var Constructor = this;
-
-  if (object && typeof object === 'object' && object.constructor === Constructor) {
-    return object;
-  }
-
-  var promise = new Constructor(noop);
-  resolve(promise, object);
-  return promise;
-}
-
-var PROMISE_ID = Math.random().toString(36).substring(2);
-
-function noop() {}
-
-var PENDING = void 0;
-var FULFILLED = 1;
-var REJECTED = 2;
-
-var TRY_CATCH_ERROR = { error: null };
-
-function selfFulfillment() {
-  return new TypeError("You cannot resolve a promise with itself");
-}
-
-function cannotReturnOwn() {
-  return new TypeError('A promises callback cannot return that same promise.');
-}
-
-function getThen(promise) {
-  try {
-    return promise.then;
-  } catch (error) {
-    TRY_CATCH_ERROR.error = error;
-    return TRY_CATCH_ERROR;
-  }
-}
-
-function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
-  try {
-    then$$1.call(value, fulfillmentHandler, rejectionHandler);
-  } catch (e) {
-    return e;
-  }
-}
-
-function handleForeignThenable(promise, thenable, then$$1) {
-  asap(function (promise) {
-    var sealed = false;
-    var error = tryThen(then$$1, thenable, function (value) {
-      if (sealed) {
-        return;
-      }
-      sealed = true;
-      if (thenable !== value) {
-        resolve(promise, value);
-      } else {
-        fulfill(promise, value);
-      }
-    }, function (reason) {
-      if (sealed) {
-        return;
-      }
-      sealed = true;
-
-      reject(promise, reason);
-    }, 'Settle: ' + (promise._label || ' unknown promise'));
-
-    if (!sealed && error) {
-      sealed = true;
-      reject(promise, error);
-    }
-  }, promise);
-}
-
-function handleOwnThenable(promise, thenable) {
-  if (thenable._state === FULFILLED) {
-    fulfill(promise, thenable._result);
-  } else if (thenable._state === REJECTED) {
-    reject(promise, thenable._result);
-  } else {
-    subscribe(thenable, undefined, function (value) {
-      return resolve(promise, value);
-    }, function (reason) {
-      return reject(promise, reason);
-    });
-  }
-}
-
-function handleMaybeThenable(promise, maybeThenable, then$$1) {
-  if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) {
-    handleOwnThenable(promise, maybeThenable);
-  } else {
-    if (then$$1 === TRY_CATCH_ERROR) {
-      reject(promise, TRY_CATCH_ERROR.error);
-      TRY_CATCH_ERROR.error = null;
-    } else if (then$$1 === undefined) {
-      fulfill(promise, maybeThenable);
-    } else if (isFunction(then$$1)) {
-      handleForeignThenable(promise, maybeThenable, then$$1);
-    } else {
-      fulfill(promise, maybeThenable);
-    }
-  }
-}
-
-function resolve(promise, value) {
-  if (promise === value) {
-    reject(promise, selfFulfillment());
-  } else if (objectOrFunction(value)) {
-    handleMaybeThenable(promise, value, getThen(value));
-  } else {
-    fulfill(promise, value);
-  }
-}
-
-function publishRejection(promise) {
-  if (promise._onerror) {
-    promise._onerror(promise._result);
-  }
-
-  publish(promise);
-}
-
-function fulfill(promise, value) {
-  if (promise._state !== PENDING) {
-    return;
-  }
-
-  promise._result = value;
-  promise._state = FULFILLED;
-
-  if (promise._subscribers.length !== 0) {
-    asap(publish, promise);
-  }
-}
-
-function reject(promise, reason) {
-  if (promise._state !== PENDING) {
-    return;
-  }
-  promise._state = REJECTED;
-  promise._result = reason;
-
-  asap(publishRejection, promise);
-}
-
-function subscribe(parent, child, onFulfillment, onRejection) {
-  var _subscribers = parent._subscribers;
-  var length = _subscribers.length;
-
-
-  parent._onerror = null;
-
-  _subscribers[length] = child;
-  _subscribers[length + FULFILLED] = onFulfillment;
-  _subscribers[length + REJECTED] = onRejection;
-
-  if (length === 0 && parent._state) {
-    asap(publish, parent);
-  }
-}
-
-function publish(promise) {
-  var subscribers = promise._subscribers;
-  var settled = promise._state;
-
-  if (subscribers.length === 0) {
-    return;
-  }
-
-  var child = void 0,
-      callback = void 0,
-      detail = promise._result;
-
-  for (var i = 0; i < subscribers.length; i += 3) {
-    child = subscribers[i];
-    callback = subscribers[i + settled];
-
-    if (child) {
-      invokeCallback(settled, child, callback, detail);
-    } else {
-      callback(detail);
-    }
-  }
-
-  promise._subscribers.length = 0;
-}
-
-function tryCatch(callback, detail) {
-  try {
-    return callback(detail);
-  } catch (e) {
-    TRY_CATCH_ERROR.error = e;
-    return TRY_CATCH_ERROR;
-  }
-}
-
-function invokeCallback(settled, promise, callback, detail) {
-  var hasCallback = isFunction(callback),
-      value = void 0,
-      error = void 0,
-      succeeded = void 0,
-      failed = void 0;
-
-  if (hasCallback) {
-    value = tryCatch(callback, detail);
-
-    if (value === TRY_CATCH_ERROR) {
-      failed = true;
-      error = value.error;
-      value.error = null;
-    } else {
-      succeeded = true;
-    }
-
-    if (promise === value) {
-      reject(promise, cannotReturnOwn());
-      return;
-    }
-  } else {
-    value = detail;
-    succeeded = true;
-  }
-
-  if (promise._state !== PENDING) {
-    // noop
-  } else if (hasCallback && succeeded) {
-    resolve(promise, value);
-  } else if (failed) {
-    reject(promise, error);
-  } else if (settled === FULFILLED) {
-    fulfill(promise, value);
-  } else if (settled === REJECTED) {
-    reject(promise, value);
-  }
-}
-
-function initializePromise(promise, resolver) {
-  try {
-    resolver(function resolvePromise(value) {
-      resolve(promise, value);
-    }, function rejectPromise(reason) {
-      reject(promise, reason);
-    });
-  } catch (e) {
-    reject(promise, e);
-  }
-}
-
-var id = 0;
-function nextId() {
-  return id++;
-}
-
-function makePromise(promise) {
-  promise[PROMISE_ID] = id++;
-  promise._state = undefined;
-  promise._result = undefined;
-  promise._subscribers = [];
-}
-
-function validationError() {
-  return new Error('Array Methods must be provided an Array');
-}
-
-var Enumerator = function () {
-  function Enumerator(Constructor, input) {
-    this._instanceConstructor = Constructor;
-    this.promise = new Constructor(noop);
-
-    if (!this.promise[PROMISE_ID]) {
-      makePromise(this.promise);
-    }
-
-    if (isArray(input)) {
-      this.length = input.length;
-      this._remaining = input.length;
-
-      this._result = new Array(this.length);
-
-      if (this.length === 0) {
-        fulfill(this.promise, this._result);
-      } else {
-        this.length = this.length || 0;
-        this._enumerate(input);
-        if (this._remaining === 0) {
-          fulfill(this.promise, this._result);
-        }
-      }
-    } else {
-      reject(this.promise, validationError());
-    }
-  }
-
-  Enumerator.prototype._enumerate = function _enumerate(input) {
-    for (var i = 0; this._state === PENDING && i < input.length; i++) {
-      this._eachEntry(input[i], i);
-    }
-  };
-
-  Enumerator.prototype._eachEntry = function _eachEntry(entry, i) {
-    var c = this._instanceConstructor;
-    var resolve$$1 = c.resolve;
-
-
-    if (resolve$$1 === resolve$1) {
-      var _then = getThen(entry);
-
-      if (_then === then && entry._state !== PENDING) {
-        this._settledAt(entry._state, i, entry._result);
-      } else if (typeof _then !== 'function') {
-        this._remaining--;
-        this._result[i] = entry;
-      } else if (c === Promise$1) {
-        var promise = new c(noop);
-        handleMaybeThenable(promise, entry, _then);
-        this._willSettleAt(promise, i);
-      } else {
-        this._willSettleAt(new c(function (resolve$$1) {
-          return resolve$$1(entry);
-        }), i);
-      }
-    } else {
-      this._willSettleAt(resolve$$1(entry), i);
-    }
-  };
-
-  Enumerator.prototype._settledAt = function _settledAt(state, i, value) {
-    var promise = this.promise;
-
-
-    if (promise._state === PENDING) {
-      this._remaining--;
-
-      if (state === REJECTED) {
-        reject(promise, value);
-      } else {
-        this._result[i] = value;
-      }
-    }
-
-    if (this._remaining === 0) {
-      fulfill(promise, this._result);
-    }
-  };
-
-  Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i) {
-    var enumerator = this;
-
-    subscribe(promise, undefined, function (value) {
-      return enumerator._settledAt(FULFILLED, i, value);
-    }, function (reason) {
-      return enumerator._settledAt(REJECTED, i, reason);
-    });
-  };
-
-  return Enumerator;
-}();
-
-/**
-  `Promise.all` accepts an array of promises, and returns a new promise which
-  is fulfilled with an array of fulfillment values for the passed promises, or
-  rejected with the reason of the first passed promise to be rejected. It casts all
-  elements of the passed iterable to promises as it runs this algorithm.
-
-  Example:
-
-  ```javascript
-  let promise1 = resolve(1);
-  let promise2 = resolve(2);
-  let promise3 = resolve(3);
-  let promises = [ promise1, promise2, promise3 ];
-
-  Promise.all(promises).then(function(array){
-    // The array here would be [ 1, 2, 3 ];
-  });
-  ```
-
-  If any of the `promises` given to `all` are rejected, the first promise
-  that is rejected will be given as an argument to the returned promises's
-  rejection handler. For example:
-
-  Example:
-
-  ```javascript
-  let promise1 = resolve(1);
-  let promise2 = reject(new Error("2"));
-  let promise3 = reject(new Error("3"));
-  let promises = [ promise1, promise2, promise3 ];
-
-  Promise.all(promises).then(function(array){
-    // Code here never runs because there are rejected promises!
-  }, function(error) {
-    // error.message === "2"
-  });
-  ```
-
-  @method all
-  @static
-  @param {Array} entries array of promises
-  @param {String} label optional string for labeling the promise.
-  Useful for tooling.
-  @return {Promise} promise that is fulfilled when all `promises` have been
-  fulfilled, or rejected if any of them become rejected.
-  @static
-*/
-function all(entries) {
-  return new Enumerator(this, entries).promise;
-}
-
-/**
-  `Promise.race` returns a new promise which is settled in the same way as the
-  first passed promise to settle.
-
-  Example:
-
-  ```javascript
-  let promise1 = new Promise(function(resolve, reject){
-    setTimeout(function(){
-      resolve('promise 1');
-    }, 200);
-  });
-
-  let promise2 = new Promise(function(resolve, reject){
-    setTimeout(function(){
-      resolve('promise 2');
-    }, 100);
-  });
-
-  Promise.race([promise1, promise2]).then(function(result){
-    // result === 'promise 2' because it was resolved before promise1
-    // was resolved.
-  });
-  ```
-
-  `Promise.race` is deterministic in that only the state of the first
-  settled promise matters. For example, even if other promises given to the
-  `promises` array argument are resolved, but the first settled promise has
-  become rejected before the other promises became fulfilled, the returned
-  promise will become rejected:
-
-  ```javascript
-  let promise1 = new Promise(function(resolve, reject){
-    setTimeout(function(){
-      resolve('promise 1');
-    }, 200);
-  });
-
-  let promise2 = new Promise(function(resolve, reject){
-    setTimeout(function(){
-      reject(new Error('promise 2'));
-    }, 100);
-  });
-
-  Promise.race([promise1, promise2]).then(function(result){
-    // Code here never runs
-  }, function(reason){
-    // reason.message === 'promise 2' because promise 2 became rejected before
-    // promise 1 became fulfilled
-  });
-  ```
-
-  An example real-world use case is implementing timeouts:
-
-  ```javascript
-  Promise.race([ajax('foo.json'), timeout(5000)])
-  ```
-
-  @method race
-  @static
-  @param {Array} promises array of promises to observe
-  Useful for tooling.
-  @return {Promise} a promise which settles in the same way as the first passed
-  promise to settle.
-*/
-function race(entries) {
-  /*jshint validthis:true */
-  var Constructor = this;
-
-  if (!isArray(entries)) {
-    return new Constructor(function (_, reject) {
-      return reject(new TypeError('You must pass an array to race.'));
-    });
-  } else {
-    return new Constructor(function (resolve, reject) {
-      var length = entries.length;
-      for (var i = 0; i < length; i++) {
-        Constructor.resolve(entries[i]).then(resolve, reject);
-      }
-    });
-  }
-}
-
-/**
-  `Promise.reject` returns a promise rejected with the passed `reason`.
-  It is shorthand for the following:
-
-  ```javascript
-  let promise = new Promise(function(resolve, reject){
-    reject(new Error('WHOOPS'));
-  });
-
-  promise.then(function(value){
-    // Code here doesn't run because the promise is rejected!
-  }, function(reason){
-    // reason.message === 'WHOOPS'
-  });
-  ```
-
-  Instead of writing the above, your code now simply becomes the following:
-
-  ```javascript
-  let promise = Promise.reject(new Error('WHOOPS'));
-
-  promise.then(function(value){
-    // Code here doesn't run because the promise is rejected!
-  }, function(reason){
-    // reason.message === 'WHOOPS'
-  });
-  ```
-
-  @method reject
-  @static
-  @param {Any} reason value that the returned promise will be rejected with.
-  Useful for tooling.
-  @return {Promise} a promise rejected with the given `reason`.
-*/
-function reject$1(reason) {
-  /*jshint validthis:true */
-  var Constructor = this;
-  var promise = new Constructor(noop);
-  reject(promise, reason);
-  return promise;
-}
-
-function needsResolver() {
-  throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
-}
-
-function needsNew() {
-  throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
-}
-
-/**
-  Promise objects represent the eventual result of an asynchronous operation. The
-  primary way of interacting with a promise is through its `then` method, which
-  registers callbacks to receive either a promise's eventual value or the reason
-  why the promise cannot be fulfilled.
-
-  Terminology
-  -----------
-
-  - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
-  - `thenable` is an object or function that defines a `then` method.
-  - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
-  - `exception` is a value that is thrown using the throw statement.
-  - `reason` is a value that indicates why a promise was rejected.
-  - `settled` the final resting state of a promise, fulfilled or rejected.
-
-  A promise can be in one of three states: pending, fulfilled, or rejected.
-
-  Promises that are fulfilled have a fulfillment value and are in the fulfilled
-  state.  Promises that are rejected have a rejection reason and are in the
-  rejected state.  A fulfillment value is never a thenable.
-
-  Promises can also be said to *resolve* a value.  If this value is also a
-  promise, then the original promise's settled state will match the value's
-  settled state.  So a promise that *resolves* a promise that rejects will
-  itself reject, and a promise that *resolves* a promise that fulfills will
-  itself fulfill.
-
-
-  Basic Usage:
-  ------------
-
-  ```js
-  let promise = new Promise(function(resolve, reject) {
-    // on success
-    resolve(value);
-
-    // on failure
-    reject(reason);
-  });
-
-  promise.then(function(value) {
-    // on fulfillment
-  }, function(reason) {
-    // on rejection
-  });
-  ```
-
-  Advanced Usage:
-  ---------------
-
-  Promises shine when abstracting away asynchronous interactions such as
-  `XMLHttpRequest`s.
-
-  ```js
-  function getJSON(url) {
-    return new Promise(function(resolve, reject){
-      let xhr = new XMLHttpRequest();
-
-      xhr.open('GET', url);
-      xhr.onreadystatechange = handler;
-      xhr.responseType = 'json';
-      xhr.setRequestHeader('Accept', 'application/json');
-      xhr.send();
-
-      function handler() {
-        if (this.readyState === this.DONE) {
-          if (this.status === 200) {
-            resolve(this.response);
-          } else {
-            reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
-          }
-        }
-      };
-    });
-  }
-
-  getJSON('/posts.json').then(function(json) {
-    // on fulfillment
-  }, function(reason) {
-    // on rejection
-  });
-  ```
-
-  Unlike callbacks, promises are great composable primitives.
-
-  ```js
-  Promise.all([
-    getJSON('/posts'),
-    getJSON('/comments')
-  ]).then(function(values){
-    values[0] // => postsJSON
-    values[1] // => commentsJSON
-
-    return values;
-  });
-  ```
-
-  @class Promise
-  @param {Function} resolver
-  Useful for tooling.
-  @constructor
-*/
-
-var Promise$1 = function () {
-  function Promise(resolver) {
-    this[PROMISE_ID] = nextId();
-    this._result = this._state = undefined;
-    this._subscribers = [];
-
-    if (noop !== resolver) {
-      typeof resolver !== 'function' && needsResolver();
-      this instanceof Promise ? initializePromise(this, resolver) : needsNew();
-    }
-  }
-
-  /**
-  The primary way of interacting with a promise is through its `then` method,
-  which registers callbacks to receive either a promise's eventual value or the
-  reason why the promise cannot be fulfilled.
-   ```js
-  findUser().then(function(user){
-    // user is available
-  }, function(reason){
-    // user is unavailable, and you are given the reason why
-  });
-  ```
-   Chaining
-  --------
-   The return value of `then` is itself a promise.  This second, 'downstream'
-  promise is resolved with the return value of the first promise's fulfillment
-  or rejection handler, or rejected if the handler throws an exception.
-   ```js
-  findUser().then(function (user) {
-    return user.name;
-  }, function (reason) {
-    return 'default name';
-  }).then(function (userName) {
-    // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
-    // will be `'default name'`
-  });
-   findUser().then(function (user) {
-    throw new Error('Found user, but still unhappy');
-  }, function (reason) {
-    throw new Error('`findUser` rejected and we're unhappy');
-  }).then(function (value) {
-    // never reached
-  }, function (reason) {
-    // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
-    // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
-  });
-  ```
-  If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
-   ```js
-  findUser().then(function (user) {
-    throw new PedagogicalException('Upstream error');
-  }).then(function (value) {
-    // never reached
-  }).then(function (value) {
-    // never reached
-  }, function (reason) {
-    // The `PedgagocialException` is propagated all the way down to here
-  });
-  ```
-   Assimilation
-  ------------
-   Sometimes the value you want to propagate to a downstream promise can only be
-  retrieved asynchronously. This can be achieved by returning a promise in the
-  fulfillment or rejection handler. The downstream promise will then be pending
-  until the returned promise is settled. This is called *assimilation*.
-   ```js
-  findUser().then(function (user) {
-    return findCommentsByAuthor(user);
-  }).then(function (comments) {
-    // The user's comments are now available
-  });
-  ```
-   If the assimliated promise rejects, then the downstream promise will also reject.
-   ```js
-  findUser().then(function (user) {
-    return findCommentsByAuthor(user);
-  }).then(function (comments) {
-    // If `findCommentsByAuthor` fulfills, we'll have the value here
-  }, function (reason) {
-    // If `findCommentsByAuthor` rejects, we'll have the reason here
-  });
-  ```
-   Simple Example
-  --------------
-   Synchronous Example
-   ```javascript
-  let result;
-   try {
-    result = findResult();
-    // success
-  } catch(reason) {
-    // failure
-  }
-  ```
-   Errback Example
-   ```js
-  findResult(function(result, err){
-    if (err) {
-      // failure
-    } else {
-      // success
-    }
-  });
-  ```
-   Promise Example;
-   ```javascript
-  findResult().then(function(result){
-    // success
-  }, function(reason){
-    // failure
-  });
-  ```
-   Advanced Example
-  --------------
-   Synchronous Example
-   ```javascript
-  let author, books;
-   try {
-    author = findAuthor();
-    books  = findBooksByAuthor(author);
-    // success
-  } catch(reason) {
-    // failure
-  }
-  ```
-   Errback Example
-   ```js
-   function foundBooks(books) {
-   }
-   function failure(reason) {
-   }
-   findAuthor(function(author, err){
-    if (err) {
-      failure(err);
-      // failure
-    } else {
-      try {
-        findBoooksByAuthor(author, function(books, err) {
-          if (err) {
-            failure(err);
-          } else {
-            try {
-              foundBooks(books);
-            } catch(reason) {
-              failure(reason);
-            }
-          }
-        });
-      } catch(error) {
-        failure(err);
-      }
-      // success
-    }
-  });
-  ```
-   Promise Example;
-   ```javascript
-  findAuthor().
-    then(findBooksByAuthor).
-    then(function(books){
-      // found books
-  }).catch(function(reason){
-    // something went wrong
-  });
-  ```
-   @method then
-  @param {Function} onFulfilled
-  @param {Function} onRejected
-  Useful for tooling.
-  @return {Promise}
-  */
-
-  /**
-  `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
-  as the catch block of a try/catch statement.
-  ```js
-  function findAuthor(){
-  throw new Error('couldn't find that author');
-  }
-  // synchronous
-  try {
-  findAuthor();
-  } catch(reason) {
-  // something went wrong
-  }
-  // async with promises
-  findAuthor().catch(function(reason){
-  // something went wrong
-  });
-  ```
-  @method catch
-  @param {Function} onRejection
-  Useful for tooling.
-  @return {Promise}
-  */
-
-
-  Promise.prototype.catch = function _catch(onRejection) {
-    return this.then(null, onRejection);
-  };
-
-  /**
-    `finally` will be invoked regardless of the promise's fate just as native
-    try/catch/finally behaves
-  
-    Synchronous example:
-  
-    ```js
-    findAuthor() {
-      if (Math.random() > 0.5) {
-        throw new Error();
-      }
-      return new Author();
-    }
-  
-    try {
-      return findAuthor(); // succeed or fail
-    } catch(error) {
-      return findOtherAuther();
-    } finally {
-      // always runs
-      // doesn't affect the return value
-    }
-    ```
-  
-    Asynchronous example:
-  
-    ```js
-    findAuthor().catch(function(reason){
-      return findOtherAuther();
-    }).finally(function(){
-      // author was either found, or not
-    });
-    ```
-  
-    @method finally
-    @param {Function} callback
-    @return {Promise}
-  */
-
-
-  Promise.prototype.finally = function _finally(callback) {
-    var promise = this;
-    var constructor = promise.constructor;
-
-    if (isFunction(callback)) {
-      return promise.then(function (value) {
-        return constructor.resolve(callback()).then(function () {
-          return value;
-        });
-      }, function (reason) {
-        return constructor.resolve(callback()).then(function () {
-          throw reason;
-        });
-      });
-    }
-
-    return promise.then(callback, callback);
-  };
-
-  return Promise;
-}();
-
-Promise$1.prototype.then = then;
-Promise$1.all = all;
-Promise$1.race = race;
-Promise$1.resolve = resolve$1;
-Promise$1.reject = reject$1;
-Promise$1._setScheduler = setScheduler;
-Promise$1._setAsap = setAsap;
-Promise$1._asap = asap;
-
-/*global self*/
-function polyfill() {
-  var local = void 0;
-
-  if (typeof global !== 'undefined') {
-    local = global;
-  } else if (typeof self !== 'undefined') {
-    local = self;
-  } else {
-    try {
-      local = Function('return this')();
-    } catch (e) {
-      throw new Error('polyfill failed because global object is unavailable in this environment');
-    }
-  }
-
-  var P = local.Promise;
-
-  if (P) {
-    var promiseToString = null;
-    try {
-      promiseToString = Object.prototype.toString.call(P.resolve());
-    } catch (e) {
-      // silently ignored
-    }
-
-    if (promiseToString === '[object Promise]' && !P.cast) {
-      return;
-    }
-  }
-
-  local.Promise = Promise$1;
-}
-
-// Strange compat..
-Promise$1.polyfill = polyfill;
-Promise$1.Promise = Promise$1;
-
-return Promise$1;
-
-})));
-
-
-
-
-
-}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-
-},{"_process":3}],2:[function(_dereq_,module,exports){
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-function EventEmitter() {
-  this._events = this._events || {};
-  this._maxListeners = this._maxListeners || undefined;
-}
-module.exports = EventEmitter;
-
-// Backwards-compat with node 0.10.x
-EventEmitter.EventEmitter = EventEmitter;
-
-EventEmitter.prototype._events = undefined;
-EventEmitter.prototype._maxListeners = undefined;
-
-// By default EventEmitters will print a warning if more than 10 listeners are
-// added to it. This is a useful default which helps finding memory leaks.
-EventEmitter.defaultMaxListeners = 10;
-
-// Obviously not all Emitters should be limited to 10. This function allows
-// that to be increased. Set to zero for unlimited.
-EventEmitter.prototype.setMaxListeners = function(n) {
-  if (!isNumber(n) || n < 0 || isNaN(n))
-    throw TypeError('n must be a positive number');
-  this._maxListeners = n;
-  return this;
-};
-
-EventEmitter.prototype.emit = function(type) {
-  var er, handler, len, args, i, listeners;
-
-  if (!this._events)
-    this._events = {};
-
-  // If there is no 'error' event listener then throw.
-  if (type === 'error') {
-    if (!this._events.error ||
-        (isObject(this._events.error) && !this._events.error.length)) {
-      er = arguments[1];
-      if (er instanceof Error) {
-        throw er; // Unhandled 'error' event
-      } else {
-        // At least give some kind of context to the user
-        var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
-        err.context = er;
-        throw err;
-      }
-    }
-  }
-
-  handler = this._events[type];
-
-  if (isUndefined(handler))
-    return false;
-
-  if (isFunction(handler)) {
-    switch (arguments.length) {
-      // fast cases
-      case 1:
-        handler.call(this);
-        break;
-      case 2:
-        handler.call(this, arguments[1]);
-        break;
-      case 3:
-        handler.call(this, arguments[1], arguments[2]);
-        break;
-      // slower
-      default:
-        args = Array.prototype.slice.call(arguments, 1);
-        handler.apply(this, args);
-    }
-  } else if (isObject(handler)) {
-    args = Array.prototype.slice.call(arguments, 1);
-    listeners = handler.slice();
-    len = listeners.length;
-    for (i = 0; i < len; i++)
-      listeners[i].apply(this, args);
-  }
-
-  return true;
-};
-
-EventEmitter.prototype.addListener = function(type, listener) {
-  var m;
-
-  if (!isFunction(listener))
-    throw TypeError('listener must be a function');
-
-  if (!this._events)
-    this._events = {};
-
-  // To avoid recursion in the case that type === "newListener"! Before
-  // adding it to the listeners, first emit "newListener".
-  if (this._events.newListener)
-    this.emit('newListener', type,
-              isFunction(listener.listener) ?
-              listener.listener : listener);
-
-  if (!this._events[type])
-    // Optimize the case of one listener. Don't need the extra array object.
-    this._events[type] = listener;
-  else if (isObject(this._events[type]))
-    // If we've already got an array, just append.
-    this._events[type].push(listener);
-  else
-    // Adding the second element, need to change to array.
-    this._events[type] = [this._events[type], listener];
-
-  // Check for listener leak
-  if (isObject(this._events[type]) && !this._events[type].warned) {
-    if (!isUndefined(this._maxListeners)) {
-      m = this._maxListeners;
-    } else {
-      m = EventEmitter.defaultMaxListeners;
-    }
-
-    if (m && m > 0 && this._events[type].length > m) {
-      this._events[type].warned = true;
-      console.error('(node) warning: possible EventEmitter memory ' +
-                    'leak detected. %d listeners added. ' +
-                    'Use emitter.setMaxListeners() to increase limit.',
-                    this._events[type].length);
-      if (typeof console.trace === 'function') {
-        // not supported in IE 10
-        console.trace();
-      }
-    }
-  }
-
-  return this;
-};
-
-EventEmitter.prototype.on = EventEmitter.prototype.addListener;
-
-EventEmitter.prototype.once = function(type, listener) {
-  if (!isFunction(listener))
-    throw TypeError('listener must be a function');
-
-  var fired = false;
-
-  function g() {
-    this.removeListener(type, g);
-
-    if (!fired) {
-      fired = true;
-      listener.apply(this, arguments);
-    }
-  }
-
-  g.listener = listener;
-  this.on(type, g);
-
-  return this;
-};
-
-// emits a 'removeListener' event iff the listener was removed
-EventEmitter.prototype.removeListener = function(type, listener) {
-  var list, position, length, i;
-
-  if (!isFunction(listener))
-    throw TypeError('listener must be a function');
-
-  if (!this._events || !this._events[type])
-    return this;
-
-  list = this._events[type];
-  length = list.length;
-  position = -1;
-
-  if (list === listener ||
-      (isFunction(list.listener) && list.listener === listener)) {
-    delete this._events[type];
-    if (this._events.removeListener)
-      this.emit('removeListener', type, listener);
-
-  } else if (isObject(list)) {
-    for (i = length; i-- > 0;) {
-      if (list[i] === listener ||
-          (list[i].listener && list[i].listener === listener)) {
-        position = i;
-        break;
-      }
-    }
-
-    if (position < 0)
-      return this;
-
-    if (list.length === 1) {
-      list.length = 0;
-      delete this._events[type];
-    } else {
-      list.splice(position, 1);
-    }
-
-    if (this._events.removeListener)
-      this.emit('removeListener', type, listener);
-  }
-
-  return this;
-};
-
-EventEmitter.prototype.removeAllListeners = function(type) {
-  var key, listeners;
-
-  if (!this._events)
-    return this;
-
-  // not listening for removeListener, no need to emit
-  if (!this._events.removeListener) {
-    if (arguments.length === 0)
-      this._events = {};
-    else if (this._events[type])
-      delete this._events[type];
-    return this;
-  }
-
-  // emit removeListener for all listeners on all events
-  if (arguments.length === 0) {
-    for (key in this._events) {
-      if (key === 'removeListener') continue;
-      this.removeAllListeners(key);
-    }
-    this.removeAllListeners('removeListener');
-    this._events = {};
-    return this;
-  }
-
-  listeners = this._events[type];
-
-  if (isFunction(listeners)) {
-    this.removeListener(type, listeners);
-  } else if (listeners) {
-    // LIFO order
-    while (listeners.length)
-      this.removeListener(type, listeners[listeners.length - 1]);
-  }
-  delete this._events[type];
-
-  return this;
-};
-
-EventEmitter.prototype.listeners = function(type) {
-  var ret;
-  if (!this._events || !this._events[type])
-    ret = [];
-  else if (isFunction(this._events[type]))
-    ret = [this._events[type]];
-  else
-    ret = this._events[type].slice();
-  return ret;
-};
-
-EventEmitter.prototype.listenerCount = function(type) {
-  if (this._events) {
-    var evlistener = this._events[type];
-
-    if (isFunction(evlistener))
-      return 1;
-    else if (evlistener)
-      return evlistener.length;
-  }
-  return 0;
-};
-
-EventEmitter.listenerCount = function(emitter, type) {
-  return emitter.listenerCount(type);
-};
-
-function isFunction(arg) {
-  return typeof arg === 'function';
-}
-
-function isNumber(arg) {
-  return typeof arg === 'number';
-}
-
-function isObject(arg) {
-  return typeof arg === 'object' && arg !== null;
-}
-
-function isUndefined(arg) {
-  return arg === void 0;
-}
-
-},{}],3:[function(_dereq_,module,exports){
-// shim for using process in browser
-var process = module.exports = {};
-
-// cached from whatever global is present so that test runners that stub it
-// don't break things.  But we need to wrap it in a try catch in case it is
-// wrapped in strict mode code which doesn't define any globals.  It's inside a
-// function because try/catches deoptimize in certain engines.
-
-var cachedSetTimeout;
-var cachedClearTimeout;
-
-function defaultSetTimout() {
-    throw new Error('setTimeout has not been defined');
-}
-function defaultClearTimeout () {
-    throw new Error('clearTimeout has not been defined');
-}
-(function () {
-    try {
-        if (typeof setTimeout === 'function') {
-            cachedSetTimeout = setTimeout;
-        } else {
-            cachedSetTimeout = defaultSetTimout;
-        }
-    } catch (e) {
-        cachedSetTimeout = defaultSetTimout;
-    }
-    try {
-        if (typeof clearTimeout === 'function') {
-            cachedClearTimeout = clearTimeout;
-        } else {
-            cachedClearTimeout = defaultClearTimeout;
-        }
-    } catch (e) {
-        cachedClearTimeout = defaultClearTimeout;
-    }
-} ())
-function runTimeout(fun) {
-    if (cachedSetTimeout === setTimeout) {
-        //normal enviroments in sane situations
-        return setTimeout(fun, 0);
-    }
-    // if setTimeout wasn't available but was latter defined
-    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
-        cachedSetTimeout = setTimeout;
-        return setTimeout(fun, 0);
-    }
-    try {
-        // when when somebody has screwed with setTimeout but no I.E. maddness
-        return cachedSetTimeout(fun, 0);
-    } catch(e){
-        try {
-            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
-            return cachedSetTimeout.call(null, fun, 0);
-        } catch(e){
-            // 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
-            return cachedSetTimeout.call(this, fun, 0);
-        }
-    }
-
-
-}
-function runClearTimeout(marker) {
-    if (cachedClearTimeout === clearTimeout) {
-        //normal enviroments in sane situations
-        return clearTimeout(marker);
-    }
-    // if clearTimeout wasn't available but was latter defined
-    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
-        cachedClearTimeout = clearTimeout;
-        return clearTimeout(marker);
-    }
-    try {
-        // when when somebody has screwed with setTimeout but no I.E. maddness
-        return cachedClearTimeout(marker);
-    } catch (e){
-        try {
-            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
-            return cachedClearTimeout.call(null, marker);
-        } catch (e){
-            // 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.
-            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
-            return cachedClearTimeout.call(this, marker);
-        }
-    }
-
-
-
-}
-var queue = [];
-var draining = false;
-var currentQueue;
-var queueIndex = -1;
-
-function cleanUpNextTick() {
-    if (!draining || !currentQueue) {
-        return;
-    }
-    draining = false;
-    if (currentQueue.length) {
-        queue = currentQueue.concat(queue);
-    } else {
-        queueIndex = -1;
-    }
-    if (queue.length) {
-        drainQueue();
-    }
-}
-
-function drainQueue() {
-    if (draining) {
-        return;
-    }
-    var timeout = runTimeout(cleanUpNextTick);
-    draining = true;
-
-    var len = queue.length;
-    while(len) {
-        currentQueue = queue;
-        queue = [];
-        while (++queueIndex < len) {
-            if (currentQueue) {
-                currentQueue[queueIndex].run();
-            }
-        }
-        queueIndex = -1;
-        len = queue.length;
-    }
-    currentQueue = null;
-    draining = false;
-    runClearTimeout(timeout);
-}
-
-process.nextTick = function (fun) {
-    var args = new Array(arguments.length - 1);
-    if (arguments.length > 1) {
-        for (var i = 1; i < arguments.length; i++) {
-            args[i - 1] = arguments[i];
-        }
-    }
-    queue.push(new Item(fun, args));
-    if (queue.length === 1 && !draining) {
-        runTimeout(drainQueue);
-    }
-};
-
-// v8 likes predictible objects
-function Item(fun, array) {
-    this.fun = fun;
-    this.array = array;
-}
-Item.prototype.run = function () {
-    this.fun.apply(null, this.array);
-};
-process.title = 'browser';
-process.browser = true;
-process.env = {};
-process.argv = [];
-process.version = ''; // empty string to avoid regexp issues
-process.versions = {};
-
-function noop() {}
-
-process.on = noop;
-process.addListener = noop;
-process.once = noop;
-process.off = noop;
-process.removeListener = noop;
-process.removeAllListeners = noop;
-process.emit = noop;
-process.prependListener = noop;
-process.prependOnceListener = noop;
-
-process.listeners = function (name) { return [] }
-
-process.binding = function (name) {
-    throw new Error('process.binding is not supported');
-};
-
-process.cwd = function () { return '/' };
-process.chdir = function (dir) {
-    throw new Error('process.chdir is not supported');
-};
-process.umask = function() { return 0; };
-
-},{}],4:[function(_dereq_,module,exports){
-var bundleFn = arguments[3];
-var sources = arguments[4];
-var cache = arguments[5];
-
-var stringify = JSON.stringify;
-
-module.exports = function (fn, options) {
-    var wkey;
-    var cacheKeys = Object.keys(cache);
-
-    for (var i = 0, l = cacheKeys.length; i < l; i++) {
-        var key = cacheKeys[i];
-        var exp = cache[key].exports;
-        // Using babel as a transpiler to use esmodule, the export will always
-        // be an object with the default export as a property of it. To ensure
-        // the existing api and babel esmodule exports are both supported we
-        // check for both
-        if (exp === fn || exp && exp.default === fn) {
-            wkey = key;
-            break;
-        }
-    }
-
-    if (!wkey) {
-        wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
-        var wcache = {};
-        for (var i = 0, l = cacheKeys.length; i < l; i++) {
-            var key = cacheKeys[i];
-            wcache[key] = key;
-        }
-        sources[wkey] = [
-            'function(require,module,exports){' + fn + '(self); }',
-            wcache
-        ];
-    }
-    var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
-
-    var scache = {}; scache[wkey] = wkey;
-    sources[skey] = [
-        'function(require,module,exports){' +
-            // try to call default if defined to also support babel esmodule exports
-            'var f = require(' + stringify(wkey) + ');' +
-            '(f.default ? f.default : f)(self);' +
-        '}',
-        scache
-    ];
-
-    var workerSources = {};
-    resolveSources(skey);
-
-    function resolveSources(key) {
-        workerSources[key] = true;
-
-        for (var depPath in sources[key][1]) {
-            var depKey = sources[key][1][depPath];
-            if (!workerSources[depKey]) {
-                resolveSources(depKey);
-            }
-        }
-    }
-
-    var src = '(' + bundleFn + ')({'
-        + Object.keys(workerSources).map(function (key) {
-            return stringify(key) + ':['
-                + sources[key][0]
-                + ',' + stringify(sources[key][1]) + ']'
-            ;
-        }).join(',')
-        + '},{},[' + stringify(skey) + '])'
-    ;
-
-    var URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
-
-    var blob = new Blob([src], { type: 'text/javascript' });
-    if (options && options.bare) { return blob; }
-    var workerUrl = URL.createObjectURL(blob);
-    var worker = new Worker(workerUrl);
-    worker.objectURL = workerUrl;
-    return worker;
-};
-
-},{}],5:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-exports.createDefaultConfig = createDefaultConfig;
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var defaultConfig = exports.defaultConfig = {
-    enableWorker: false,
-    enableStashBuffer: true,
-    stashInitialSize: undefined,
-
-    isLive: false,
-
-    lazyLoad: true,
-    lazyLoadMaxDuration: 3 * 60,
-    lazyLoadRecoverDuration: 30,
-    deferLoadAfterSourceOpen: true,
-
-    // autoCleanupSourceBuffer: default as false, leave unspecified
-    autoCleanupMaxBackwardDuration: 3 * 60,
-    autoCleanupMinBackwardDuration: 2 * 60,
-
-    statisticsInfoReportInterval: 600,
-
-    fixAudioTimestampGap: true,
-
-    accurateSeek: false,
-    seekType: 'range', // [range, param, custom]
-    seekParamStart: 'bstart',
-    seekParamEnd: 'bend',
-    rangeLoadZeroStart: false,
-    customSeekHandler: undefined,
-    reuseRedirectedURL: false,
-    // referrerPolicy: leave as unspecified
-
-    headers: undefined,
-    customLoader: undefined
-};
-
-function createDefaultConfig() {
-    return Object.assign({}, defaultConfig);
-}
-
-},{}],6:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
-
-var _ioController = _dereq_('../io/io-controller.js');
-
-var _ioController2 = _interopRequireDefault(_ioController);
-
-var _config = _dereq_('../config.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-var Features = function () {
-    function Features() {
-        _classCallCheck(this, Features);
-    }
-
-    _createClass(Features, null, [{
-        key: 'supportMSEH264Playback',
-        value: function supportMSEH264Playback() {
-            return window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');
-        }
-    }, {
-        key: 'supportNetworkStreamIO',
-        value: function supportNetworkStreamIO() {
-            var ioctl = new _ioController2.default({}, (0, _config.createDefaultConfig)());
-            var loaderType = ioctl.loaderType;
-            ioctl.destroy();
-            return loaderType == 'fetch-stream-loader' || loaderType == 'xhr-moz-chunked-loader';
-        }
-    }, {
-        key: 'getNetworkLoaderTypeName',
-        value: function getNetworkLoaderTypeName() {
-            var ioctl = new _ioController2.default({}, (0, _config.createDefaultConfig)());
-            var loaderType = ioctl.loaderType;
-            ioctl.destroy();
-            return loaderType;
-        }
-    }, {
-        key: 'supportNativeMediaPlayback',
-        value: function supportNativeMediaPlayback(mimeType) {
-            if (Features.videoElement == undefined) {
-                Features.videoElement = window.document.createElement('video');
-            }
-            var canPlay = Features.videoElement.canPlayType(mimeType);
-            return canPlay === 'probably' || canPlay == 'maybe';
-        }
-    }, {
-        key: 'getFeatureList',
-        value: function getFeatureList() {
-            var features = {
-                mseFlvPlayback: false,
-                mseLiveFlvPlayback: false,
-                networkStreamIO: false,
-                networkLoaderName: '',
-                nativeMP4H264Playback: false,
-                nativeWebmVP8Playback: false,
-                nativeWebmVP9Playback: false
-            };
-
-            features.mseFlvPlayback = Features.supportMSEH264Playback();
-            features.networkStreamIO = Features.supportNetworkStreamIO();
-            features.networkLoaderName = Features.getNetworkLoaderTypeName();
-            features.mseLiveFlvPlayback = features.mseFlvPlayback && features.networkStreamIO;
-            features.nativeMP4H264Playback = Features.supportNativeMediaPlayback('video/mp4; codecs="avc1.42001E, mp4a.40.2"');
-            features.nativeWebmVP8Playback = Features.supportNativeMediaPlayback('video/webm; codecs="vp8.0, vorbis"');
-            features.nativeWebmVP9Playback = Features.supportNativeMediaPlayback('video/webm; codecs="vp9"');
-
-            return features;
-        }
-    }]);
-
-    return Features;
-}();
-
-exports.default = Features;
-
-},{"../config.js":5,"../io/io-controller.js":23}],7:[function(_dereq_,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var MediaInfo = function () {
-    function MediaInfo() {
-        _classCallCheck(this, MediaInfo);
-
-        this.mimeType = null;
-        this.duration = null;
-
-        this.hasAudio = null;
-        this.hasVideo = null;
-        this.audioCodec = null;
-        this.videoCodec = null;
-        this.audioDataRate = null;
-        this.videoDataRate = null;
-
-        this.audioSampleRate = null;
-        this.audioChannelCount = 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;
-
-        this.metadata = null;
-        this.segments = null; // MediaInfo[]
-        this.segmentCount = null;
-        this.hasKeyframesIndex = null;
-        this.keyframesIndex = null;
-    }
-
-    _createClass(MediaInfo, [{
-        key: "isComplete",
-        value: function isComplete() {
-            var audioInfoComplete = this.hasAudio === false || this.hasAudio === true && this.audioCodec != null && this.audioSampleRate != null && this.audioChannelCount != null;
-
-            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;
-
-            // keyframesIndex may not be present
-            return this.mimeType != null && this.duration != null && this.metadata != null && this.hasKeyframesIndex != null && audioInfoComplete && videoInfoComplete;
-        }
-    }, {
-        key: "isSeekable",
-        value: function isSeekable() {
-            return this.hasKeyframesIndex === true;
-        }
-    }, {
-        key: "getNearestKeyframe",
-        value: function getNearestKeyframe(milliseconds) {
-            if (this.keyframesIndex == null) {
-                return null;
-            }
-
-            var table = this.keyframesIndex;
-            var keyframeIdx = this._search(table.times, milliseconds);
-
-            return {
-                index: keyframeIdx,
-                milliseconds: table.times[keyframeIdx],
-                fileposition: table.filepositions[keyframeIdx]
-            };
-        }
-    }, {
-        key: "_search",
-        value: function _search(list, value) {
-            var idx = 0;
-
-            var last = list.length - 1;
-            var mid = 0;
-            var lbound = 0;
-            var ubound = last;
-
-            if (value < list[0]) {
-                idx = 0;
-                lbound = ubound + 1; // skip search
-            }
-
-            while (lbound <= ubound) {
-                mid = lbound + Math.floor((ubound - lbound) / 2);
-                if (mid === last || value >= list[mid] && value < list[mid + 1]) {
-                    idx = mid;
-                    break;
-                } else if (list[mid] < value) {
-                    lbound = mid + 1;
-                } else {
-                    ubound = mid - 1;
-                }
-            }
-
-            return idx;
-        }
-    }]);
-
-    return MediaInfo;
-}();
-
-exports.default = MediaInfo;
-
-},{}],8:[function(_dereq_,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Represents an media sample (audio / video)
-var SampleInfo = exports.SampleInfo = function SampleInfo(dts, pts, duration, originalDts, isSync) {
-    _classCallCheck(this, SampleInfo);
-
-    this.dts = dts;
-    this.pts = pts;
-    this.duration = duration;
-    this.originalDts = originalDts;
-    this.isSyncPoint = isSync;
-    this.fileposition = null;
-};
-
-// Media Segment concept is defined in Media Source Extensions spec.
-// Particularly in ISO BMFF format, an Media Segment contains a moof box followed by a mdat box.
-
-
-var MediaSegmentInfo = exports.MediaSegmentInfo = function () {
-    function MediaSegmentInfo() {
-        _classCallCheck(this, MediaSegmentInfo);
-
-        this.beginDts = 0;
-        this.endDts = 0;
-        this.beginPts = 0;
-        this.endPts = 0;
-        this.originalBeginDts = 0;
-        this.originalEndDts = 0;
-        this.syncPoints = []; // SampleInfo[n], for video IDR frames only
-        this.firstSample = null; // SampleInfo
-        this.lastSample = null; // SampleInfo
-    }
-
-    _createClass(MediaSegmentInfo, [{
-        key: "appendSyncPoint",
-        value: function appendSyncPoint(sampleInfo) {
-            // also called Random Access Point
-            sampleInfo.isSyncPoint = true;
-            this.syncPoints.push(sampleInfo);
-        }
-    }]);
-
-    return MediaSegmentInfo;
-}();
-
-// Ordered list for recording video IDR frames, sorted by originalDts
-
-
-var IDRSampleList = exports.IDRSampleList = function () {
-    function IDRSampleList() {
-        _classCallCheck(this, IDRSampleList);
-
-        this._list = [];
-    }
-
-    _createClass(IDRSampleList, [{
-        key: "clear",
-        value: function clear() {
-            this._list = [];
-        }
-    }, {
-        key: "appendArray",
-        value: function appendArray(syncPoints) {
-            var list = this._list;
-
-            if (syncPoints.length === 0) {
-                return;
-            }
-
-            if (list.length > 0 && syncPoints[0].originalDts < list[list.length - 1].originalDts) {
-                this.clear();
-            }
-
-            Array.prototype.push.apply(list, syncPoints);
-        }
-    }, {
-        key: "getLastSyncPointBeforeDts",
-        value: function getLastSyncPointBeforeDts(dts) {
-            if (this._list.length == 0) {
-                return null;
-            }
-
-            var list = this._list;
-            var idx = 0;
-            var last = list.length - 1;
-            var mid = 0;
-            var lbound = 0;
-            var ubound = last;
-
-            if (dts < list[0].dts) {
-                idx = 0;
-                lbound = ubound + 1;
-            }
-
-            while (lbound <= ubound) {
-                mid = lbound + Math.floor((ubound - lbound) / 2);
-                if (mid === last || dts >= list[mid].dts && dts < list[mid + 1].dts) {
-                    idx = mid;
-                    break;
-                } else if (list[mid].dts < dts) {
-                    lbound = mid + 1;
-                } else {
-                    ubound = mid - 1;
-                }
-            }
-            return this._list[idx];
-        }
-    }]);
-
-    return IDRSampleList;
-}();
-
-// Data structure for recording information of media segments in single track.
-
-
-var MediaSegmentInfoList = exports.MediaSegmentInfoList = function () {
-    function MediaSegmentInfoList(type) {
-        _classCallCheck(this, MediaSegmentInfoList);
-
-        this._type = type;
-        this._list = [];
-        this._lastAppendLocation = -1; // cached last insert location
-    }
-
-    _createClass(MediaSegmentInfoList, [{
-        key: "isEmpty",
-        value: function isEmpty() {
-            return this._list.length === 0;
-        }
-    }, {
-        key: "clear",
-        value: function clear() {
-            this._list = [];
-            this._lastAppendLocation = -1;
-        }
-    }, {
-        key: "_searchNearestSegmentBefore",
-        value: function _searchNearestSegmentBefore(originalBeginDts) {
-            var list = this._list;
-            if (list.length === 0) {
-                return -2;
-            }
-            var last = list.length - 1;
-            var mid = 0;
-            var lbound = 0;
-            var ubound = last;
-
-            var idx = 0;
-
-            if (originalBeginDts < list[0].originalBeginDts) {
-                idx = -1;
-                return idx;
-            }
-
-            while (lbound <= ubound) {
-                mid = lbound + Math.floor((ubound - lbound) / 2);
-                if (mid === last || originalBeginDts > list[mid].lastSample.originalDts && originalBeginDts < list[mid + 1].originalBeginDts) {
-                    idx = mid;
-                    break;
-                } else if (list[mid].originalBeginDts < originalBeginDts) {
-                    lbound = mid + 1;
-                } else {
-                    ubound = mid - 1;
-                }
-            }
-            return idx;
-        }
-    }, {
-        key: "_searchNearestSegmentAfter",
-        value: function _searchNearestSegmentAfter(originalBeginDts) {
-            return this._searchNearestSegmentBefore(originalBeginDts) + 1;
-        }
-    }, {
-        key: "append",
-        value: function append(mediaSegmentInfo) {
-            var list = this._list;
-            var msi = mediaSegmentInfo;
-            var lastAppendIdx = this._lastAppendLocation;
-            var insertIdx = 0;
-
-            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)) {
-                insertIdx = lastAppendIdx + 1; // use cached location idx
-            } else {
-                if (list.length > 0) {
-                    insertIdx = this._searchNearestSegmentBefore(msi.originalBeginDts) + 1;
-                }
-            }
-
-            this._lastAppendLocation = insertIdx;
-            this._list.splice(insertIdx, 0, msi);
-        }
-    }, {
-        key: "getLastSegmentBefore",
-        value: function getLastSegmentBefore(originalBeginDts) {
-            var idx = this._searchNearestSegmentBefore(originalBeginDts);
-            if (idx >= 0) {
-                return this._list[idx];
-            } else {
-                // -1
-                return null;
-            }
-        }
-    }, {
-        key: "getLastSampleBefore",
-        value: function getLastSampleBefore(originalBeginDts) {
-            var segment = this.getLastSegmentBefore(originalBeginDts);
-            if (segment != null) {
-                return segment.lastSample;
-            } else {
-                return null;
-            }
-        }
-    }, {
-        key: "getLastSyncPointBefore",
-        value: function getLastSyncPointBefore(originalBeginDts) {
-            var segmentIdx = this._searchNearestSegmentBefore(originalBeginDts);
-            var syncPoints = this._list[segmentIdx].syncPoints;
-            while (syncPoints.length === 0 && segmentIdx > 0) {
-                segmentIdx--;
-                syncPoints = this._list[segmentIdx].syncPoints;
-            }
-            if (syncPoints.length > 0) {
-                return syncPoints[syncPoints.length - 1];
-            } else {
-                return null;
-            }
-        }
-    }, {
-        key: "type",
-        get: function get() {
-            return this._type;
-        }
-    }, {
-        key: "length",
-        get: function get() {
-            return this._list.length;
-        }
-    }]);
-
-    return MediaSegmentInfoList;
-}();
-
-},{}],9:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
-
-var _events = _dereq_('events');
-
-var _events2 = _interopRequireDefault(_events);
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _browser = _dereq_('../utils/browser.js');
-
-var _browser2 = _interopRequireDefault(_browser);
-
-var _mseEvents = _dereq_('./mse-events.js');
-
-var _mseEvents2 = _interopRequireDefault(_mseEvents);
-
-var _mediaSegmentInfo = _dereq_('./media-segment-info.js');
-
-var _exception = _dereq_('../utils/exception.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-// Media Source Extensions controller
-var MSEController = function () {
-    function MSEController(config) {
-        _classCallCheck(this, MSEController);
-
-        this.TAG = 'MSEController';
-
-        this._config = config;
-        this._emitter = new _events2.default();
-
-        if (this._config.isLive && this._config.autoCleanupSourceBuffer == undefined) {
-            // For live stream, do auto cleanup by default
-            this._config.autoCleanupSourceBuffer = true;
-        }
-
-        this.e = {
-            onSourceOpen: this._onSourceOpen.bind(this),
-            onSourceEnded: this._onSourceEnded.bind(this),
-            onSourceClose: this._onSourceClose.bind(this),
-            onSourceBufferError: this._onSourceBufferError.bind(this),
-            onSourceBufferUpdateEnd: this._onSourceBufferUpdateEnd.bind(this)
-        };
-
-        this._mediaSource = null;
-        this._mediaSourceObjectURL = null;
-        this._mediaElement = null;
-
-        this._isBufferFull = false;
-        this._hasPendingEos = false;
-
-        this._requireSetMediaDuration = false;
-        this._pendingMediaDuration = 0;
-
-        this._pendingSourceBufferInit = [];
-        this._mimeTypes = {
-            video: null,
-            audio: null
-        };
-        this._sourceBuffers = {
-            video: null,
-            audio: null
-        };
-        this._lastInitSegments = {
-            video: null,
-            audio: null
-        };
-        this._pendingSegments = {
-            video: [],
-            audio: []
-        };
-        this._pendingRemoveRanges = {
-            video: [],
-            audio: []
-        };
-        this._idrList = new _mediaSegmentInfo.IDRSampleList();
-    }
-
-    _createClass(MSEController, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this._mediaElement || this._mediaSource) {
-                this.detachMediaElement();
-            }
-            this.e = null;
-            this._emitter.removeAllListeners();
-            this._emitter = null;
-        }
-    }, {
-        key: 'on',
-        value: function on(event, listener) {
-            this._emitter.addListener(event, listener);
-        }
-    }, {
-        key: 'off',
-        value: function off(event, listener) {
-            this._emitter.removeListener(event, listener);
-        }
-    }, {
-        key: 'attachMediaElement',
-        value: function attachMediaElement(mediaElement) {
-            if (this._mediaSource) {
-                throw new _exception.IllegalStateException('MediaSource has been attached to an HTMLMediaElement!');
-            }
-            var ms = this._mediaSource = new window.MediaSource();
-            ms.addEventListener('sourceopen', this.e.onSourceOpen);
-            ms.addEventListener('sourceended', this.e.onSourceEnded);
-            ms.addEventListener('sourceclose', this.e.onSourceClose);
-
-            this._mediaElement = mediaElement;
-            this._mediaSourceObjectURL = window.URL.createObjectURL(this._mediaSource);
-            mediaElement.src = this._mediaSourceObjectURL;
-        }
-    }, {
-        key: 'detachMediaElement',
-        value: function detachMediaElement() {
-            if (this._mediaSource) {
-                var ms = this._mediaSource;
-                for (var type in this._sourceBuffers) {
-                    // pending segments should be discard
-                    var ps = this._pendingSegments[type];
-                    ps.splice(0, ps.length);
-                    this._pendingSegments[type] = null;
-                    this._pendingRemoveRanges[type] = null;
-                    this._lastInitSegments[type] = null;
-
-                    // remove all sourcebuffers
-                    var sb = this._sourceBuffers[type];
-                    if (sb) {
-                        if (ms.readyState !== 'closed') {
-                            // ms edge can throw an error: Unexpected call to method or property access
-                            try {
-                                ms.removeSourceBuffer(sb);
-                            } catch (error) {
-                                _logger2.default.e(this.TAG, error.message);
+                    var asap = function asap(callback, arg) {
+                        queue[len] = callback;
+                        queue[len + 1] = arg;
+                        len += 2;
+                        if (len === 2) {
+                            // If len is 2, that means that we need to schedule an async flush.
+                            // If additional callbacks are queued before the queue is flushed, they
+                            // will be processed by this flush that we are scheduling.
+                            if (customSchedulerFn) {
+                                customSchedulerFn(flush);
+                            } else {
+                                scheduleFlush();
                             }
-                            sb.removeEventListener('error', this.e.onSourceBufferError);
-                            sb.removeEventListener('updateend', this.e.onSourceBufferUpdateEnd);
                         }
-                        this._mimeTypes[type] = null;
-                        this._sourceBuffers[type] = null;
+                    };
+
+                    function setScheduler(scheduleFn) {
+                        customSchedulerFn = scheduleFn;
+                    }
+
+                    function setAsap(asapFn) {
+                        asap = asapFn;
+                    }
+
+                    var browserWindow = typeof window !== 'undefined' ? window : undefined;
+                    var browserGlobal = browserWindow || {};
+                    var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
+                    var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
+
+                    // test for web worker but not in IE10
+                    var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
+
+                    // node
+                    function useNextTick() {
+                        // node version 0.10.x displays a deprecation warning when nextTick is used recursively
+                        // see https://github.com/cujojs/when/issues/410 for details
+                        return function () {
+                            return process.nextTick(flush);
+                        };
+                    }
+
+                    // vertx
+                    function useVertxTimer() {
+                        if (typeof vertxNext !== 'undefined') {
+                            return function () {
+                                vertxNext(flush);
+                            };
+                        }
+
+                        return useSetTimeout();
+                    }
+
+                    function useMutationObserver() {
+                        var iterations = 0;
+                        var observer = new BrowserMutationObserver(flush);
+                        var node = document.createTextNode('');
+                        observer.observe(node, { characterData: true });
+
+                        return function () {
+                            node.data = iterations = ++iterations % 2;
+                        };
+                    }
+
+                    // web worker
+                    function useMessageChannel() {
+                        var channel = new MessageChannel();
+                        channel.port1.onmessage = flush;
+                        return function () {
+                            return channel.port2.postMessage(0);
+                        };
+                    }
+
+                    function useSetTimeout() {
+                        // Store setTimeout reference so es6-promise will be unaffected by
+                        // other code modifying setTimeout (like sinon.useFakeTimers())
+                        var globalSetTimeout = setTimeout;
+                        return function () {
+                            return globalSetTimeout(flush, 1);
+                        };
+                    }
+
+                    var queue = new Array(1000);
+                    function flush() {
+                        for (var i = 0; i < len; i += 2) {
+                            var callback = queue[i];
+                            var arg = queue[i + 1];
+
+                            callback(arg);
+
+                            queue[i] = undefined;
+                            queue[i + 1] = undefined;
+                        }
+
+                        len = 0;
+                    }
+
+                    function attemptVertx() {
+                        try {
+                            var vertx = Function('return this')().require('vertx');
+                            vertxNext = vertx.runOnLoop || vertx.runOnContext;
+                            return useVertxTimer();
+                        } catch (e) {
+                            return useSetTimeout();
+                        }
+                    }
+
+                    var scheduleFlush = void 0;
+                    // Decide what async method to use to triggering processing of queued callbacks:
+                    if (isNode) {
+                        scheduleFlush = useNextTick();
+                    } else if (BrowserMutationObserver) {
+                        scheduleFlush = useMutationObserver();
+                    } else if (isWorker) {
+                        scheduleFlush = useMessageChannel();
+                    } else if (browserWindow === undefined && typeof _dereq_ === 'function') {
+                        scheduleFlush = attemptVertx();
+                    } else {
+                        scheduleFlush = useSetTimeout();
+                    }
+
+                    function then(onFulfillment, onRejection) {
+                        var parent = this;
+
+                        var child = new this.constructor(noop);
+
+                        if (child[PROMISE_ID] === undefined) {
+                            makePromise(child);
+                        }
+
+                        var _state = parent._state;
+
+
+                        if (_state) {
+                            var callback = arguments[_state - 1];
+                            asap(function () {
+                                return invokeCallback(_state, child, callback, parent._result);
+                            });
+                        } else {
+                            subscribe(parent, child, onFulfillment, onRejection);
+                        }
+
+                        return child;
+                    }
+
+                    /**
+                      `Promise.resolve` returns a promise that will become resolved with the
+                      passed `value`. It is shorthand for the following:
+                    
+                      ```javascript
+                      let promise = new Promise(function(resolve, reject){
+                        resolve(1);
+                      });
+                    
+                      promise.then(function(value){
+                        // value === 1
+                      });
+                      ```
+                    
+                      Instead of writing the above, your code now simply becomes the following:
+                    
+                      ```javascript
+                      let promise = Promise.resolve(1);
+                    
+                      promise.then(function(value){
+                        // value === 1
+                      });
+                      ```
+                    
+                      @method resolve
+                      @static
+                      @param {Any} value value that the returned promise will be resolved with
+                      Useful for tooling.
+                      @return {Promise} a promise that will become fulfilled with the given
+                      `value`
+                    */
+                    function resolve$1(object) {
+                        /*jshint validthis:true */
+                        var Constructor = this;
+
+                        if (object && typeof object === 'object' && object.constructor === Constructor) {
+                            return object;
+                        }
+
+                        var promise = new Constructor(noop);
+                        resolve(promise, object);
+                        return promise;
+                    }
+
+                    var PROMISE_ID = Math.random().toString(36).substring(2);
+
+                    function noop() { }
+
+                    var PENDING = void 0;
+                    var FULFILLED = 1;
+                    var REJECTED = 2;
+
+                    var TRY_CATCH_ERROR = { error: null };
+
+                    function selfFulfillment() {
+                        return new TypeError("You cannot resolve a promise with itself");
+                    }
+
+                    function cannotReturnOwn() {
+                        return new TypeError('A promises callback cannot return that same promise.');
+                    }
+
+                    function getThen(promise) {
+                        try {
+                            return promise.then;
+                        } catch (error) {
+                            TRY_CATCH_ERROR.error = error;
+                            return TRY_CATCH_ERROR;
+                        }
+                    }
+
+                    function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
+                        try {
+                            then$$1.call(value, fulfillmentHandler, rejectionHandler);
+                        } catch (e) {
+                            return e;
+                        }
+                    }
+
+                    function handleForeignThenable(promise, thenable, then$$1) {
+                        asap(function (promise) {
+                            var sealed = false;
+                            var error = tryThen(then$$1, thenable, function (value) {
+                                if (sealed) {
+                                    return;
+                                }
+                                sealed = true;
+                                if (thenable !== value) {
+                                    resolve(promise, value);
+                                } else {
+                                    fulfill(promise, value);
+                                }
+                            }, function (reason) {
+                                if (sealed) {
+                                    return;
+                                }
+                                sealed = true;
+
+                                reject(promise, reason);
+                            }, 'Settle: ' + (promise._label || ' unknown promise'));
+
+                            if (!sealed && error) {
+                                sealed = true;
+                                reject(promise, error);
+                            }
+                        }, promise);
+                    }
+
+                    function handleOwnThenable(promise, thenable) {
+                        if (thenable._state === FULFILLED) {
+                            fulfill(promise, thenable._result);
+                        } else if (thenable._state === REJECTED) {
+                            reject(promise, thenable._result);
+                        } else {
+                            subscribe(thenable, undefined, function (value) {
+                                return resolve(promise, value);
+                            }, function (reason) {
+                                return reject(promise, reason);
+                            });
+                        }
+                    }
+
+                    function handleMaybeThenable(promise, maybeThenable, then$$1) {
+                        if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) {
+                            handleOwnThenable(promise, maybeThenable);
+                        } else {
+                            if (then$$1 === TRY_CATCH_ERROR) {
+                                reject(promise, TRY_CATCH_ERROR.error);
+                                TRY_CATCH_ERROR.error = null;
+                            } else if (then$$1 === undefined) {
+                                fulfill(promise, maybeThenable);
+                            } else if (isFunction(then$$1)) {
+                                handleForeignThenable(promise, maybeThenable, then$$1);
+                            } else {
+                                fulfill(promise, maybeThenable);
+                            }
+                        }
+                    }
+
+                    function resolve(promise, value) {
+                        if (promise === value) {
+                            reject(promise, selfFulfillment());
+                        } else if (objectOrFunction(value)) {
+                            handleMaybeThenable(promise, value, getThen(value));
+                        } else {
+                            fulfill(promise, value);
+                        }
+                    }
+
+                    function publishRejection(promise) {
+                        if (promise._onerror) {
+                            promise._onerror(promise._result);
+                        }
+
+                        publish(promise);
+                    }
+
+                    function fulfill(promise, value) {
+                        if (promise._state !== PENDING) {
+                            return;
+                        }
+
+                        promise._result = value;
+                        promise._state = FULFILLED;
+
+                        if (promise._subscribers.length !== 0) {
+                            asap(publish, promise);
+                        }
+                    }
+
+                    function reject(promise, reason) {
+                        if (promise._state !== PENDING) {
+                            return;
+                        }
+                        promise._state = REJECTED;
+                        promise._result = reason;
+
+                        asap(publishRejection, promise);
+                    }
+
+                    function subscribe(parent, child, onFulfillment, onRejection) {
+                        var _subscribers = parent._subscribers;
+                        var length = _subscribers.length;
+
+
+                        parent._onerror = null;
+
+                        _subscribers[length] = child;
+                        _subscribers[length + FULFILLED] = onFulfillment;
+                        _subscribers[length + REJECTED] = onRejection;
+
+                        if (length === 0 && parent._state) {
+                            asap(publish, parent);
+                        }
+                    }
+
+                    function publish(promise) {
+                        var subscribers = promise._subscribers;
+                        var settled = promise._state;
+
+                        if (subscribers.length === 0) {
+                            return;
+                        }
+
+                        var child = void 0,
+                            callback = void 0,
+                            detail = promise._result;
+
+                        for (var i = 0; i < subscribers.length; i += 3) {
+                            child = subscribers[i];
+                            callback = subscribers[i + settled];
+
+                            if (child) {
+                                invokeCallback(settled, child, callback, detail);
+                            } else {
+                                callback(detail);
+                            }
+                        }
+
+                        promise._subscribers.length = 0;
+                    }
+
+                    function tryCatch(callback, detail) {
+                        try {
+                            return callback(detail);
+                        } catch (e) {
+                            TRY_CATCH_ERROR.error = e;
+                            return TRY_CATCH_ERROR;
+                        }
+                    }
+
+                    function invokeCallback(settled, promise, callback, detail) {
+                        var hasCallback = isFunction(callback),
+                            value = void 0,
+                            error = void 0,
+                            succeeded = void 0,
+                            failed = void 0;
+
+                        if (hasCallback) {
+                            value = tryCatch(callback, detail);
+
+                            if (value === TRY_CATCH_ERROR) {
+                                failed = true;
+                                error = value.error;
+                                value.error = null;
+                            } else {
+                                succeeded = true;
+                            }
+
+                            if (promise === value) {
+                                reject(promise, cannotReturnOwn());
+                                return;
+                            }
+                        } else {
+                            value = detail;
+                            succeeded = true;
+                        }
+
+                        if (promise._state !== PENDING) {
+                            // noop
+                        } else if (hasCallback && succeeded) {
+                            resolve(promise, value);
+                        } else if (failed) {
+                            reject(promise, error);
+                        } else if (settled === FULFILLED) {
+                            fulfill(promise, value);
+                        } else if (settled === REJECTED) {
+                            reject(promise, value);
+                        }
+                    }
+
+                    function initializePromise(promise, resolver) {
+                        try {
+                            resolver(function resolvePromise(value) {
+                                resolve(promise, value);
+                            }, function rejectPromise(reason) {
+                                reject(promise, reason);
+                            });
+                        } catch (e) {
+                            reject(promise, e);
+                        }
+                    }
+
+                    var id = 0;
+                    function nextId() {
+                        return id++;
+                    }
+
+                    function makePromise(promise) {
+                        promise[PROMISE_ID] = id++;
+                        promise._state = undefined;
+                        promise._result = undefined;
+                        promise._subscribers = [];
+                    }
+
+                    function validationError() {
+                        return new Error('Array Methods must be provided an Array');
+                    }
+
+                    var Enumerator = function () {
+                        function Enumerator(Constructor, input) {
+                            this._instanceConstructor = Constructor;
+                            this.promise = new Constructor(noop);
+
+                            if (!this.promise[PROMISE_ID]) {
+                                makePromise(this.promise);
+                            }
+
+                            if (isArray(input)) {
+                                this.length = input.length;
+                                this._remaining = input.length;
+
+                                this._result = new Array(this.length);
+
+                                if (this.length === 0) {
+                                    fulfill(this.promise, this._result);
+                                } else {
+                                    this.length = this.length || 0;
+                                    this._enumerate(input);
+                                    if (this._remaining === 0) {
+                                        fulfill(this.promise, this._result);
+                                    }
+                                }
+                            } else {
+                                reject(this.promise, validationError());
+                            }
+                        }
+
+                        Enumerator.prototype._enumerate = function _enumerate(input) {
+                            for (var i = 0; this._state === PENDING && i < input.length; i++) {
+                                this._eachEntry(input[i], i);
+                            }
+                        };
+
+                        Enumerator.prototype._eachEntry = function _eachEntry(entry, i) {
+                            var c = this._instanceConstructor;
+                            var resolve$$1 = c.resolve;
+
+
+                            if (resolve$$1 === resolve$1) {
+                                var _then = getThen(entry);
+
+                                if (_then === then && entry._state !== PENDING) {
+                                    this._settledAt(entry._state, i, entry._result);
+                                } else if (typeof _then !== 'function') {
+                                    this._remaining--;
+                                    this._result[i] = entry;
+                                } else if (c === Promise$1) {
+                                    var promise = new c(noop);
+                                    handleMaybeThenable(promise, entry, _then);
+                                    this._willSettleAt(promise, i);
+                                } else {
+                                    this._willSettleAt(new c(function (resolve$$1) {
+                                        return resolve$$1(entry);
+                                    }), i);
+                                }
+                            } else {
+                                this._willSettleAt(resolve$$1(entry), i);
+                            }
+                        };
+
+                        Enumerator.prototype._settledAt = function _settledAt(state, i, value) {
+                            var promise = this.promise;
+
+
+                            if (promise._state === PENDING) {
+                                this._remaining--;
+
+                                if (state === REJECTED) {
+                                    reject(promise, value);
+                                } else {
+                                    this._result[i] = value;
+                                }
+                            }
+
+                            if (this._remaining === 0) {
+                                fulfill(promise, this._result);
+                            }
+                        };
+
+                        Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i) {
+                            var enumerator = this;
+
+                            subscribe(promise, undefined, function (value) {
+                                return enumerator._settledAt(FULFILLED, i, value);
+                            }, function (reason) {
+                                return enumerator._settledAt(REJECTED, i, reason);
+                            });
+                        };
+
+                        return Enumerator;
+                    }();
+
+                    /**
+                      `Promise.all` accepts an array of promises, and returns a new promise which
+                      is fulfilled with an array of fulfillment values for the passed promises, or
+                      rejected with the reason of the first passed promise to be rejected. It casts all
+                      elements of the passed iterable to promises as it runs this algorithm.
+                    
+                      Example:
+                    
+                      ```javascript
+                      let promise1 = resolve(1);
+                      let promise2 = resolve(2);
+                      let promise3 = resolve(3);
+                      let promises = [ promise1, promise2, promise3 ];
+                    
+                      Promise.all(promises).then(function(array){
+                        // The array here would be [ 1, 2, 3 ];
+                      });
+                      ```
+                    
+                      If any of the `promises` given to `all` are rejected, the first promise
+                      that is rejected will be given as an argument to the returned promises's
+                      rejection handler. For example:
+                    
+                      Example:
+                    
+                      ```javascript
+                      let promise1 = resolve(1);
+                      let promise2 = reject(new Error("2"));
+                      let promise3 = reject(new Error("3"));
+                      let promises = [ promise1, promise2, promise3 ];
+                    
+                      Promise.all(promises).then(function(array){
+                        // Code here never runs because there are rejected promises!
+                      }, function(error) {
+                        // error.message === "2"
+                      });
+                      ```
+                    
+                      @method all
+                      @static
+                      @param {Array} entries array of promises
+                      @param {String} label optional string for labeling the promise.
+                      Useful for tooling.
+                      @return {Promise} promise that is fulfilled when all `promises` have been
+                      fulfilled, or rejected if any of them become rejected.
+                      @static
+                    */
+                    function all(entries) {
+                        return new Enumerator(this, entries).promise;
+                    }
+
+                    /**
+                      `Promise.race` returns a new promise which is settled in the same way as the
+                      first passed promise to settle.
+                    
+                      Example:
+                    
+                      ```javascript
+                      let promise1 = new Promise(function(resolve, reject){
+                        setTimeout(function(){
+                          resolve('promise 1');
+                        }, 200);
+                      });
+                    
+                      let promise2 = new Promise(function(resolve, reject){
+                        setTimeout(function(){
+                          resolve('promise 2');
+                        }, 100);
+                      });
+                    
+                      Promise.race([promise1, promise2]).then(function(result){
+                        // result === 'promise 2' because it was resolved before promise1
+                        // was resolved.
+                      });
+                      ```
+                    
+                      `Promise.race` is deterministic in that only the state of the first
+                      settled promise matters. For example, even if other promises given to the
+                      `promises` array argument are resolved, but the first settled promise has
+                      become rejected before the other promises became fulfilled, the returned
+                      promise will become rejected:
+                    
+                      ```javascript
+                      let promise1 = new Promise(function(resolve, reject){
+                        setTimeout(function(){
+                          resolve('promise 1');
+                        }, 200);
+                      });
+                    
+                      let promise2 = new Promise(function(resolve, reject){
+                        setTimeout(function(){
+                          reject(new Error('promise 2'));
+                        }, 100);
+                      });
+                    
+                      Promise.race([promise1, promise2]).then(function(result){
+                        // Code here never runs
+                      }, function(reason){
+                        // reason.message === 'promise 2' because promise 2 became rejected before
+                        // promise 1 became fulfilled
+                      });
+                      ```
+                    
+                      An example real-world use case is implementing timeouts:
+                    
+                      ```javascript
+                      Promise.race([ajax('foo.json'), timeout(5000)])
+                      ```
+                    
+                      @method race
+                      @static
+                      @param {Array} promises array of promises to observe
+                      Useful for tooling.
+                      @return {Promise} a promise which settles in the same way as the first passed
+                      promise to settle.
+                    */
+                    function race(entries) {
+                        /*jshint validthis:true */
+                        var Constructor = this;
+
+                        if (!isArray(entries)) {
+                            return new Constructor(function (_, reject) {
+                                return reject(new TypeError('You must pass an array to race.'));
+                            });
+                        } else {
+                            return new Constructor(function (resolve, reject) {
+                                var length = entries.length;
+                                for (var i = 0; i < length; i++) {
+                                    Constructor.resolve(entries[i]).then(resolve, reject);
+                                }
+                            });
+                        }
+                    }
+
+                    /**
+                      `Promise.reject` returns a promise rejected with the passed `reason`.
+                      It is shorthand for the following:
+                    
+                      ```javascript
+                      let promise = new Promise(function(resolve, reject){
+                        reject(new Error('WHOOPS'));
+                      });
+                    
+                      promise.then(function(value){
+                        // Code here doesn't run because the promise is rejected!
+                      }, function(reason){
+                        // reason.message === 'WHOOPS'
+                      });
+                      ```
+                    
+                      Instead of writing the above, your code now simply becomes the following:
+                    
+                      ```javascript
+                      let promise = Promise.reject(new Error('WHOOPS'));
+                    
+                      promise.then(function(value){
+                        // Code here doesn't run because the promise is rejected!
+                      }, function(reason){
+                        // reason.message === 'WHOOPS'
+                      });
+                      ```
+                    
+                      @method reject
+                      @static
+                      @param {Any} reason value that the returned promise will be rejected with.
+                      Useful for tooling.
+                      @return {Promise} a promise rejected with the given `reason`.
+                    */
+                    function reject$1(reason) {
+                        /*jshint validthis:true */
+                        var Constructor = this;
+                        var promise = new Constructor(noop);
+                        reject(promise, reason);
+                        return promise;
+                    }
+
+                    function needsResolver() {
+                        throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
+                    }
+
+                    function needsNew() {
+                        throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
+                    }
+
+                    /**
+                      Promise objects represent the eventual result of an asynchronous operation. The
+                      primary way of interacting with a promise is through its `then` method, which
+                      registers callbacks to receive either a promise's eventual value or the reason
+                      why the promise cannot be fulfilled.
+                    
+                      Terminology
+                      -----------
+                    
+                      - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
+                      - `thenable` is an object or function that defines a `then` method.
+                      - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
+                      - `exception` is a value that is thrown using the throw statement.
+                      - `reason` is a value that indicates why a promise was rejected.
+                      - `settled` the final resting state of a promise, fulfilled or rejected.
+                    
+                      A promise can be in one of three states: pending, fulfilled, or rejected.
+                    
+                      Promises that are fulfilled have a fulfillment value and are in the fulfilled
+                      state.  Promises that are rejected have a rejection reason and are in the
+                      rejected state.  A fulfillment value is never a thenable.
+                    
+                      Promises can also be said to *resolve* a value.  If this value is also a
+                      promise, then the original promise's settled state will match the value's
+                      settled state.  So a promise that *resolves* a promise that rejects will
+                      itself reject, and a promise that *resolves* a promise that fulfills will
+                      itself fulfill.
+                    
+                    
+                      Basic Usage:
+                      ------------
+                    
+                      ```js
+                      let promise = new Promise(function(resolve, reject) {
+                        // on success
+                        resolve(value);
+                    
+                        // on failure
+                        reject(reason);
+                      });
+                    
+                      promise.then(function(value) {
+                        // on fulfillment
+                      }, function(reason) {
+                        // on rejection
+                      });
+                      ```
+                    
+                      Advanced Usage:
+                      ---------------
+                    
+                      Promises shine when abstracting away asynchronous interactions such as
+                      `XMLHttpRequest`s.
+                    
+                      ```js
+                      function getJSON(url) {
+                        return new Promise(function(resolve, reject){
+                          let xhr = new XMLHttpRequest();
+                    
+                          xhr.open('GET', url);
+                          xhr.onreadystatechange = handler;
+                          xhr.responseType = 'json';
+                          xhr.setRequestHeader('Accept', 'application/json');
+                          xhr.send();
+                    
+                          function handler() {
+                            if (this.readyState === this.DONE) {
+                              if (this.status === 200) {
+                                resolve(this.response);
+                              } else {
+                                reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
+                              }
+                            }
+                          };
+                        });
+                      }
+                    
+                      getJSON('/posts.json').then(function(json) {
+                        // on fulfillment
+                      }, function(reason) {
+                        // on rejection
+                      });
+                      ```
+                    
+                      Unlike callbacks, promises are great composable primitives.
+                    
+                      ```js
+                      Promise.all([
+                        getJSON('/posts'),
+                        getJSON('/comments')
+                      ]).then(function(values){
+                        values[0] // => postsJSON
+                        values[1] // => commentsJSON
+                    
+                        return values;
+                      });
+                      ```
+                    
+                      @class Promise
+                      @param {Function} resolver
+                      Useful for tooling.
+                      @constructor
+                    */
+
+                    var Promise$1 = function () {
+                        function Promise(resolver) {
+                            this[PROMISE_ID] = nextId();
+                            this._result = this._state = undefined;
+                            this._subscribers = [];
+
+                            if (noop !== resolver) {
+                                typeof resolver !== 'function' && needsResolver();
+                                this instanceof Promise ? initializePromise(this, resolver) : needsNew();
+                            }
+                        }
+
+                        /**
+                        The primary way of interacting with a promise is through its `then` method,
+                        which registers callbacks to receive either a promise's eventual value or the
+                        reason why the promise cannot be fulfilled.
+                         ```js
+                        findUser().then(function(user){
+                          // user is available
+                        }, function(reason){
+                          // user is unavailable, and you are given the reason why
+                        });
+                        ```
+                         Chaining
+                        --------
+                         The return value of `then` is itself a promise.  This second, 'downstream'
+                        promise is resolved with the return value of the first promise's fulfillment
+                        or rejection handler, or rejected if the handler throws an exception.
+                         ```js
+                        findUser().then(function (user) {
+                          return user.name;
+                        }, function (reason) {
+                          return 'default name';
+                        }).then(function (userName) {
+                          // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
+                          // will be `'default name'`
+                        });
+                         findUser().then(function (user) {
+                          throw new Error('Found user, but still unhappy');
+                        }, function (reason) {
+                          throw new Error('`findUser` rejected and we're unhappy');
+                        }).then(function (value) {
+                          // never reached
+                        }, function (reason) {
+                          // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
+                          // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
+                        });
+                        ```
+                        If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
+                         ```js
+                        findUser().then(function (user) {
+                          throw new PedagogicalException('Upstream error');
+                        }).then(function (value) {
+                          // never reached
+                        }).then(function (value) {
+                          // never reached
+                        }, function (reason) {
+                          // The `PedgagocialException` is propagated all the way down to here
+                        });
+                        ```
+                         Assimilation
+                        ------------
+                         Sometimes the value you want to propagate to a downstream promise can only be
+                        retrieved asynchronously. This can be achieved by returning a promise in the
+                        fulfillment or rejection handler. The downstream promise will then be pending
+                        until the returned promise is settled. This is called *assimilation*.
+                         ```js
+                        findUser().then(function (user) {
+                          return findCommentsByAuthor(user);
+                        }).then(function (comments) {
+                          // The user's comments are now available
+                        });
+                        ```
+                         If the assimliated promise rejects, then the downstream promise will also reject.
+                         ```js
+                        findUser().then(function (user) {
+                          return findCommentsByAuthor(user);
+                        }).then(function (comments) {
+                          // If `findCommentsByAuthor` fulfills, we'll have the value here
+                        }, function (reason) {
+                          // If `findCommentsByAuthor` rejects, we'll have the reason here
+                        });
+                        ```
+                         Simple Example
+                        --------------
+                         Synchronous Example
+                         ```javascript
+                        let result;
+                         try {
+                          result = findResult();
+                          // success
+                        } catch(reason) {
+                          // failure
+                        }
+                        ```
+                         Errback Example
+                         ```js
+                        findResult(function(result, err){
+                          if (err) {
+                            // failure
+                          } else {
+                            // success
+                          }
+                        });
+                        ```
+                         Promise Example;
+                         ```javascript
+                        findResult().then(function(result){
+                          // success
+                        }, function(reason){
+                          // failure
+                        });
+                        ```
+                         Advanced Example
+                        --------------
+                         Synchronous Example
+                         ```javascript
+                        let author, books;
+                         try {
+                          author = findAuthor();
+                          books  = findBooksByAuthor(author);
+                          // success
+                        } catch(reason) {
+                          // failure
+                        }
+                        ```
+                         Errback Example
+                         ```js
+                         function foundBooks(books) {
+                         }
+                         function failure(reason) {
+                         }
+                         findAuthor(function(author, err){
+                          if (err) {
+                            failure(err);
+                            // failure
+                          } else {
+                            try {
+                              findBoooksByAuthor(author, function(books, err) {
+                                if (err) {
+                                  failure(err);
+                                } else {
+                                  try {
+                                    foundBooks(books);
+                                  } catch(reason) {
+                                    failure(reason);
+                                  }
+                                }
+                              });
+                            } catch(error) {
+                              failure(err);
+                            }
+                            // success
+                          }
+                        });
+                        ```
+                         Promise Example;
+                         ```javascript
+                        findAuthor().
+                          then(findBooksByAuthor).
+                          then(function(books){
+                            // found books
+                        }).catch(function(reason){
+                          // something went wrong
+                        });
+                        ```
+                         @method then
+                        @param {Function} onFulfilled
+                        @param {Function} onRejected
+                        Useful for tooling.
+                        @return {Promise}
+                        */
+
+                        /**
+                        `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
+                        as the catch block of a try/catch statement.
+                        ```js
+                        function findAuthor(){
+                        throw new Error('couldn't find that author');
+                        }
+                        // synchronous
+                        try {
+                        findAuthor();
+                        } catch(reason) {
+                        // something went wrong
+                        }
+                        // async with promises
+                        findAuthor().catch(function(reason){
+                        // something went wrong
+                        });
+                        ```
+                        @method catch
+                        @param {Function} onRejection
+                        Useful for tooling.
+                        @return {Promise}
+                        */
+
+
+                        Promise.prototype.catch = function _catch(onRejection) {
+                            return this.then(null, onRejection);
+                        };
+
+                        /**
+                          `finally` will be invoked regardless of the promise's fate just as native
+                          try/catch/finally behaves
+                        
+                          Synchronous example:
+                        
+                          ```js
+                          findAuthor() {
+                            if (Math.random() > 0.5) {
+                              throw new Error();
+                            }
+                            return new Author();
+                          }
+                        
+                          try {
+                            return findAuthor(); // succeed or fail
+                          } catch(error) {
+                            return findOtherAuther();
+                          } finally {
+                            // always runs
+                            // doesn't affect the return value
+                          }
+                          ```
+                        
+                          Asynchronous example:
+                        
+                          ```js
+                          findAuthor().catch(function(reason){
+                            return findOtherAuther();
+                          }).finally(function(){
+                            // author was either found, or not
+                          });
+                          ```
+                        
+                          @method finally
+                          @param {Function} callback
+                          @return {Promise}
+                        */
+
+
+                        Promise.prototype.finally = function _finally(callback) {
+                            var promise = this;
+                            var constructor = promise.constructor;
+
+                            if (isFunction(callback)) {
+                                return promise.then(function (value) {
+                                    return constructor.resolve(callback()).then(function () {
+                                        return value;
+                                    });
+                                }, function (reason) {
+                                    return constructor.resolve(callback()).then(function () {
+                                        throw reason;
+                                    });
+                                });
+                            }
+
+                            return promise.then(callback, callback);
+                        };
+
+                        return Promise;
+                    }();
+
+                    Promise$1.prototype.then = then;
+                    Promise$1.all = all;
+                    Promise$1.race = race;
+                    Promise$1.resolve = resolve$1;
+                    Promise$1.reject = reject$1;
+                    Promise$1._setScheduler = setScheduler;
+                    Promise$1._setAsap = setAsap;
+                    Promise$1._asap = asap;
+
+                    /*global self*/
+                    function polyfill() {
+                        var local = void 0;
+
+                        if (typeof global !== 'undefined') {
+                            local = global;
+                        } else if (typeof self !== 'undefined') {
+                            local = self;
+                        } else {
+                            try {
+                                local = Function('return this')();
+                            } catch (e) {
+                                throw new Error('polyfill failed because global object is unavailable in this environment');
+                            }
+                        }
+
+                        var P = local.Promise;
+
+                        if (P) {
+                            var promiseToString = null;
+                            try {
+                                promiseToString = Object.prototype.toString.call(P.resolve());
+                            } catch (e) {
+                                // silently ignored
+                            }
+
+                            if (promiseToString === '[object Promise]' && !P.cast) {
+                                return;
+                            }
+                        }
+
+                        local.Promise = Promise$1;
+                    }
+
+                    // Strange compat..
+                    Promise$1.polyfill = polyfill;
+                    Promise$1.Promise = Promise$1;
+
+                    return Promise$1;
+
+                })));
+
+
+
+
+
+            }).call(this, _dereq_('_process'), typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+        }, { "_process": 3 }], 2: [function (_dereq_, module, exports) {
+            // Copyright Joyent, Inc. and other Node contributors.
+            //
+            // Permission is hereby granted, free of charge, to any person obtaining a
+            // copy of this software and associated documentation files (the
+            // "Software"), to deal in the Software without restriction, including
+            // without limitation the rights to use, copy, modify, merge, publish,
+            // distribute, sublicense, and/or sell copies of the Software, and to permit
+            // persons to whom the Software is furnished to do so, subject to the
+            // following conditions:
+            //
+            // The above copyright notice and this permission notice shall be included
+            // in all copies or substantial portions of the Software.
+            //
+            // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+            // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+            // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+            // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+            // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+            // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+            // USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+            function EventEmitter() {
+                this._events = this._events || {};
+                this._maxListeners = this._maxListeners || undefined;
+            }
+            module.exports = EventEmitter;
+
+            // Backwards-compat with node 0.10.x
+            EventEmitter.EventEmitter = EventEmitter;
+
+            EventEmitter.prototype._events = undefined;
+            EventEmitter.prototype._maxListeners = undefined;
+
+            // By default EventEmitters will print a warning if more than 10 listeners are
+            // added to it. This is a useful default which helps finding memory leaks.
+            EventEmitter.defaultMaxListeners = 10;
+
+            // Obviously not all Emitters should be limited to 10. This function allows
+            // that to be increased. Set to zero for unlimited.
+            EventEmitter.prototype.setMaxListeners = function (n) {
+                if (!isNumber(n) || n < 0 || isNaN(n))
+                    throw TypeError('n must be a positive number');
+                this._maxListeners = n;
+                return this;
+            };
+
+            EventEmitter.prototype.emit = function (type) {
+                var er, handler, len, args, i, listeners;
+
+                if (!this._events)
+                    this._events = {};
+
+                // If there is no 'error' event listener then throw.
+                if (type === 'error') {
+                    if (!this._events.error ||
+                        (isObject(this._events.error) && !this._events.error.length)) {
+                        er = arguments[1];
+                        if (er instanceof Error) {
+                            throw er; // Unhandled 'error' event
+                        } else {
+                            // At least give some kind of context to the user
+                            //手动添加try
+                            try {
+
+                                var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
+                                err.context = er;
+                                throw err;
+                            }
+                            catch (err) {
+                                // console.log('1259报错')
+                            }
+
+                        }
                     }
                 }
-                if (ms.readyState === 'open') {
-                    try {
-                        ms.endOfStream();
-                    } catch (error) {
-                        _logger2.default.e(this.TAG, error.message);
+
+                handler = this._events[type];
+
+                if (isUndefined(handler))
+                    return false;
+
+                if (isFunction(handler)) {
+                    switch (arguments.length) {
+                        // fast cases
+                        case 1:
+                            handler.call(this);
+                            break;
+                        case 2:
+                            handler.call(this, arguments[1]);
+                            break;
+                        case 3:
+                            handler.call(this, arguments[1], arguments[2]);
+                            break;
+                        // slower
+                        default:
+                            args = Array.prototype.slice.call(arguments, 1);
+                            handler.apply(this, args);
+                    }
+                } else if (isObject(handler)) {
+                    args = Array.prototype.slice.call(arguments, 1);
+                    listeners = handler.slice();
+                    len = listeners.length;
+                    for (i = 0; i < len; i++)
+                        listeners[i].apply(this, args);
+                }
+
+                return true;
+            };
+
+            EventEmitter.prototype.addListener = function (type, listener) {
+                var m;
+
+                if (!isFunction(listener))
+                    throw TypeError('listener must be a function');
+
+                if (!this._events)
+                    this._events = {};
+
+                // To avoid recursion in the case that type === "newListener"! Before
+                // adding it to the listeners, first emit "newListener".
+                if (this._events.newListener)
+                    this.emit('newListener', type,
+                        isFunction(listener.listener) ?
+                            listener.listener : listener);
+
+                if (!this._events[type])
+                    // Optimize the case of one listener. Don't need the extra array object.
+                    this._events[type] = listener;
+                else if (isObject(this._events[type]))
+                    // If we've already got an array, just append.
+                    this._events[type].push(listener);
+                else
+                    // Adding the second element, need to change to array.
+                    this._events[type] = [this._events[type], listener];
+
+                // Check for listener leak
+                if (isObject(this._events[type]) && !this._events[type].warned) {
+                    if (!isUndefined(this._maxListeners)) {
+                        m = this._maxListeners;
+                    } else {
+                        m = EventEmitter.defaultMaxListeners;
+                    }
+
+                    if (m && m > 0 && this._events[type].length > m) {
+                        this._events[type].warned = true;
+                        console.error('(node) warning: possible EventEmitter memory ' +
+                            'leak detected. %d listeners added. ' +
+                            'Use emitter.setMaxListeners() to increase limit.',
+                            this._events[type].length);
+                        if (typeof console.trace === 'function') {
+                            // not supported in IE 10
+                            console.trace();
+                        }
                     }
                 }
-                ms.removeEventListener('sourceopen', this.e.onSourceOpen);
-                ms.removeEventListener('sourceended', this.e.onSourceEnded);
-                ms.removeEventListener('sourceclose', this.e.onSourceClose);
-                this._pendingSourceBufferInit = [];
-                this._isBufferFull = false;
-                this._idrList.clear();
-                this._mediaSource = null;
-            }
 
-            if (this._mediaElement) {
-                this._mediaElement.src = '';
-                this._mediaElement.removeAttribute('src');
-                this._mediaElement = null;
-            }
-            if (this._mediaSourceObjectURL) {
-                window.URL.revokeObjectURL(this._mediaSourceObjectURL);
-                this._mediaSourceObjectURL = null;
-            }
-        }
-    }, {
-        key: 'appendInitSegment',
-        value: function appendInitSegment(initSegment, deferred) {
-            if (!this._mediaSource || this._mediaSource.readyState !== 'open') {
-                // sourcebuffer creation requires mediaSource.readyState === 'open'
-                // so we defer the sourcebuffer creation, until sourceopen event triggered
-                this._pendingSourceBufferInit.push(initSegment);
-                // make sure that this InitSegment is in the front of pending segments queue
-                this._pendingSegments[initSegment.type].push(initSegment);
-                return;
-            }
+                return this;
+            };
 
-            var is = initSegment;
-            var mimeType = '' + is.container;
-            if (is.codec && is.codec.length > 0) {
-                mimeType += ';codecs=' + is.codec;
-            }
+            EventEmitter.prototype.on = EventEmitter.prototype.addListener;
 
-            var firstInitSegment = false;
+            EventEmitter.prototype.once = function (type, listener) {
+                if (!isFunction(listener))
+                    throw TypeError('listener must be a function');
 
-            _logger2.default.v(this.TAG, 'Received Initialization Segment, mimeType: ' + mimeType);
-            this._lastInitSegments[is.type] = is;
+                var fired = false;
 
-            if (mimeType !== this._mimeTypes[is.type]) {
-                if (!this._mimeTypes[is.type]) {
-                    // empty, first chance create sourcebuffer
-                    firstInitSegment = true;
-                    try {
-                        var sb = this._sourceBuffers[is.type] = this._mediaSource.addSourceBuffer(mimeType);
-                        sb.addEventListener('error', this.e.onSourceBufferError);
-                        sb.addEventListener('updateend', this.e.onSourceBufferUpdateEnd);
-                    } catch (error) {
-                        _logger2.default.e(this.TAG, error.message);
-                        this._emitter.emit(_mseEvents2.default.ERROR, { code: error.code, msg: error.message });
-                        return;
+                function g() {
+                    this.removeListener(type, g);
+
+                    if (!fired) {
+                        fired = true;
+                        listener.apply(this, arguments);
                     }
+                }
+
+                g.listener = listener;
+                this.on(type, g);
+
+                return this;
+            };
+
+            // emits a 'removeListener' event iff the listener was removed
+            EventEmitter.prototype.removeListener = function (type, listener) {
+                var list, position, length, i;
+
+                if (!isFunction(listener))
+                    throw TypeError('listener must be a function');
+
+                if (!this._events || !this._events[type])
+                    return this;
+
+                list = this._events[type];
+                length = list.length;
+                position = -1;
+
+                if (list === listener ||
+                    (isFunction(list.listener) && list.listener === listener)) {
+                    delete this._events[type];
+                    if (this._events.removeListener)
+                        this.emit('removeListener', type, listener);
+
+                } else if (isObject(list)) {
+                    for (i = length; i-- > 0;) {
+                        if (list[i] === listener ||
+                            (list[i].listener && list[i].listener === listener)) {
+                            position = i;
+                            break;
+                        }
+                    }
+
+                    if (position < 0)
+                        return this;
+
+                    if (list.length === 1) {
+                        list.length = 0;
+                        delete this._events[type];
+                    } else {
+                        list.splice(position, 1);
+                    }
+
+                    if (this._events.removeListener)
+                        this.emit('removeListener', type, listener);
+                }
+
+                return this;
+            };
+
+            EventEmitter.prototype.removeAllListeners = function (type) {
+                var key, listeners;
+
+                if (!this._events)
+                    return this;
+
+                // not listening for removeListener, no need to emit
+                if (!this._events.removeListener) {
+                    if (arguments.length === 0)
+                        this._events = {};
+                    else if (this._events[type])
+                        delete this._events[type];
+                    return this;
+                }
+
+                // emit removeListener for all listeners on all events
+                if (arguments.length === 0) {
+                    for (key in this._events) {
+                        if (key === 'removeListener') continue;
+                        this.removeAllListeners(key);
+                    }
+                    this.removeAllListeners('removeListener');
+                    this._events = {};
+                    return this;
+                }
+
+                listeners = this._events[type];
+
+                if (isFunction(listeners)) {
+                    this.removeListener(type, listeners);
+                } else if (listeners) {
+                    // LIFO order
+                    while (listeners.length)
+                        this.removeListener(type, listeners[listeners.length - 1]);
+                }
+                delete this._events[type];
+
+                return this;
+            };
+
+            EventEmitter.prototype.listeners = function (type) {
+                var ret;
+                if (!this._events || !this._events[type])
+                    ret = [];
+                else if (isFunction(this._events[type]))
+                    ret = [this._events[type]];
+                else
+                    ret = this._events[type].slice();
+                return ret;
+            };
+
+            EventEmitter.prototype.listenerCount = function (type) {
+                if (this._events) {
+                    var evlistener = this._events[type];
+
+                    if (isFunction(evlistener))
+                        return 1;
+                    else if (evlistener)
+                        return evlistener.length;
+                }
+                return 0;
+            };
+
+            EventEmitter.listenerCount = function (emitter, type) {
+                return emitter.listenerCount(type);
+            };
+
+            function isFunction(arg) {
+                return typeof arg === 'function';
+            }
+
+            function isNumber(arg) {
+                return typeof arg === 'number';
+            }
+
+            function isObject(arg) {
+                return typeof arg === 'object' && arg !== null;
+            }
+
+            function isUndefined(arg) {
+                return arg === void 0;
+            }
+
+        }, {}], 3: [function (_dereq_, module, exports) {
+            // shim for using process in browser
+            var process = module.exports = {};
+
+            // cached from whatever global is present so that test runners that stub it
+            // don't break things.  But we need to wrap it in a try catch in case it is
+            // wrapped in strict mode code which doesn't define any globals.  It's inside a
+            // function because try/catches deoptimize in certain engines.
+
+            var cachedSetTimeout;
+            var cachedClearTimeout;
+
+            function defaultSetTimout() {
+                throw new Error('setTimeout has not been defined');
+            }
+            function defaultClearTimeout() {
+                throw new Error('clearTimeout has not been defined');
+            }
+            (function () {
+                try {
+                    if (typeof setTimeout === 'function') {
+                        cachedSetTimeout = setTimeout;
+                    } else {
+                        cachedSetTimeout = defaultSetTimout;
+                    }
+                } catch (e) {
+                    cachedSetTimeout = defaultSetTimout;
+                }
+                try {
+                    if (typeof clearTimeout === 'function') {
+                        cachedClearTimeout = clearTimeout;
+                    } else {
+                        cachedClearTimeout = defaultClearTimeout;
+                    }
+                } catch (e) {
+                    cachedClearTimeout = defaultClearTimeout;
+                }
+            }())
+            function runTimeout(fun) {
+                if (cachedSetTimeout === setTimeout) {
+                    //normal enviroments in sane situations
+                    return setTimeout(fun, 0);
+                }
+                // if setTimeout wasn't available but was latter defined
+                if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+                    cachedSetTimeout = setTimeout;
+                    return setTimeout(fun, 0);
+                }
+                try {
+                    // when when somebody has screwed with setTimeout but no I.E. maddness
+                    return cachedSetTimeout(fun, 0);
+                } catch (e) {
+                    try {
+                        // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+                        return cachedSetTimeout.call(null, fun, 0);
+                    } catch (e) {
+                        // 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
+                        return cachedSetTimeout.call(this, fun, 0);
+                    }
+                }
+
+
+            }
+            function runClearTimeout(marker) {
+                if (cachedClearTimeout === clearTimeout) {
+                    //normal enviroments in sane situations
+                    return clearTimeout(marker);
+                }
+                // if clearTimeout wasn't available but was latter defined
+                if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+                    cachedClearTimeout = clearTimeout;
+                    return clearTimeout(marker);
+                }
+                try {
+                    // when when somebody has screwed with setTimeout but no I.E. maddness
+                    return cachedClearTimeout(marker);
+                } catch (e) {
+                    try {
+                        // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
+                        return cachedClearTimeout.call(null, marker);
+                    } catch (e) {
+                        // 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.
+                        // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+                        return cachedClearTimeout.call(this, marker);
+                    }
+                }
+
+
+
+            }
+            var queue = [];
+            var draining = false;
+            var currentQueue;
+            var queueIndex = -1;
+
+            function cleanUpNextTick() {
+                if (!draining || !currentQueue) {
+                    return;
+                }
+                draining = false;
+                if (currentQueue.length) {
+                    queue = currentQueue.concat(queue);
                 } else {
-                    _logger2.default.v(this.TAG, 'Notice: ' + is.type + ' mimeType changed, origin: ' + this._mimeTypes[is.type] + ', target: ' + mimeType);
+                    queueIndex = -1;
                 }
-                this._mimeTypes[is.type] = mimeType;
-            }
-
-            if (!deferred) {
-                // deferred means this InitSegment has been pushed to pendingSegments queue
-                this._pendingSegments[is.type].push(is);
-            }
-            if (!firstInitSegment) {
-                // append immediately only if init segment in subsequence
-                if (this._sourceBuffers[is.type] && !this._sourceBuffers[is.type].updating) {
-                    this._doAppendSegments();
+                if (queue.length) {
+                    drainQueue();
                 }
             }
-            if (_browser2.default.safari && is.container === 'audio/mpeg' && is.mediaDuration > 0) {
-                // 'audio/mpeg' track under Safari may cause MediaElement's duration to be NaN
-                // Manually correct MediaSource.duration to make progress bar seekable, and report right duration
-                this._requireSetMediaDuration = true;
-                this._pendingMediaDuration = is.mediaDuration / 1000; // in seconds
-                this._updateMediaSourceDuration();
-            }
-        }
-    }, {
-        key: 'appendMediaSegment',
-        value: function appendMediaSegment(mediaSegment) {
-            var ms = mediaSegment;
-            this._pendingSegments[ms.type].push(ms);
 
-            if (this._config.autoCleanupSourceBuffer && this._needCleanupSourceBuffer()) {
-                this._doCleanupSourceBuffer();
-            }
-
-            var sb = this._sourceBuffers[ms.type];
-            if (sb && !sb.updating && !this._hasPendingRemoveRanges()) {
-                this._doAppendSegments();
-            }
-        }
-    }, {
-        key: 'seek',
-        value: function seek(seconds) {
-            // remove all appended buffers
-            for (var type in this._sourceBuffers) {
-                if (!this._sourceBuffers[type]) {
-                    continue;
+            function drainQueue() {
+                if (draining) {
+                    return;
                 }
+                var timeout = runTimeout(cleanUpNextTick);
+                draining = true;
 
-                // abort current buffer append algorithm
-                var sb = this._sourceBuffers[type];
-                if (this._mediaSource.readyState === 'open') {
-                    try {
-                        // If range removal algorithm is running, InvalidStateError will be throwed
-                        // Ignore it.
-                        sb.abort();
-                    } catch (error) {
-                        _logger2.default.e(this.TAG, error.message);
+                var len = queue.length;
+                while (len) {
+                    currentQueue = queue;
+                    queue = [];
+                    while (++queueIndex < len) {
+                        if (currentQueue) {
+                            currentQueue[queueIndex].run();
+                        }
+                    }
+                    queueIndex = -1;
+                    len = queue.length;
+                }
+                currentQueue = null;
+                draining = false;
+                runClearTimeout(timeout);
+            }
+
+            process.nextTick = function (fun) {
+                var args = new Array(arguments.length - 1);
+                if (arguments.length > 1) {
+                    for (var i = 1; i < arguments.length; i++) {
+                        args[i - 1] = arguments[i];
+                    }
+                }
+                queue.push(new Item(fun, args));
+                if (queue.length === 1 && !draining) {
+                    runTimeout(drainQueue);
+                }
+            };
+
+            // v8 likes predictible objects
+            function Item(fun, array) {
+                this.fun = fun;
+                this.array = array;
+            }
+            Item.prototype.run = function () {
+                this.fun.apply(null, this.array);
+            };
+            process.title = 'browser';
+            process.browser = true;
+            process.env = {};
+            process.argv = [];
+            process.version = ''; // empty string to avoid regexp issues
+            process.versions = {};
+
+            function noop() { }
+
+            process.on = noop;
+            process.addListener = noop;
+            process.once = noop;
+            process.off = noop;
+            process.removeListener = noop;
+            process.removeAllListeners = noop;
+            process.emit = noop;
+            process.prependListener = noop;
+            process.prependOnceListener = noop;
+
+            process.listeners = function (name) { return [] }
+
+            process.binding = function (name) {
+                throw new Error('process.binding is not supported');
+            };
+
+            process.cwd = function () { return '/' };
+            process.chdir = function (dir) {
+                throw new Error('process.chdir is not supported');
+            };
+            process.umask = function () { return 0; };
+
+        }, {}], 4: [function (_dereq_, module, exports) {
+            var bundleFn = arguments[3];
+            var sources = arguments[4];
+            var cache = arguments[5];
+
+            var stringify = JSON.stringify;
+
+            module.exports = function (fn, options) {
+                var wkey;
+                var cacheKeys = Object.keys(cache);
+
+                for (var i = 0, l = cacheKeys.length; i < l; i++) {
+                    var key = cacheKeys[i];
+                    var exp = cache[key].exports;
+                    // Using babel as a transpiler to use esmodule, the export will always
+                    // be an object with the default export as a property of it. To ensure
+                    // the existing api and babel esmodule exports are both supported we
+                    // check for both
+                    if (exp === fn || exp && exp.default === fn) {
+                        wkey = key;
+                        break;
                     }
                 }
 
-                // IDRList should be clear
-                this._idrList.clear();
+                if (!wkey) {
+                    wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
+                    var wcache = {};
+                    for (var i = 0, l = cacheKeys.length; i < l; i++) {
+                        var key = cacheKeys[i];
+                        wcache[key] = key;
+                    }
+                    sources[wkey] = [
+                        'function(require,module,exports){' + fn + '(self); }',
+                        wcache
+                    ];
+                }
+                var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
 
-                // pending segments should be discard
-                var ps = this._pendingSegments[type];
-                ps.splice(0, ps.length);
+                var scache = {}; scache[wkey] = wkey;
+                sources[skey] = [
+                    'function(require,module,exports){' +
+                    // try to call default if defined to also support babel esmodule exports
+                    'var f = require(' + stringify(wkey) + ');' +
+                    '(f.default ? f.default : f)(self);' +
+                    '}',
+                    scache
+                ];
 
-                if (this._mediaSource.readyState === 'closed') {
-                    // Parent MediaSource object has been detached from HTMLMediaElement
-                    continue;
+                var workerSources = {};
+                resolveSources(skey);
+
+                function resolveSources(key) {
+                    workerSources[key] = true;
+
+                    for (var depPath in sources[key][1]) {
+                        var depKey = sources[key][1][depPath];
+                        if (!workerSources[depKey]) {
+                            resolveSources(depKey);
+                        }
+                    }
                 }
 
-                // record ranges to be remove from SourceBuffer
-                for (var i = 0; i < sb.buffered.length; i++) {
-                    var start = sb.buffered.start(i);
-                    var end = sb.buffered.end(i);
-                    this._pendingRemoveRanges[type].push({ start: start, end: end });
+                var src = '(' + bundleFn + ')({'
+                    + Object.keys(workerSources).map(function (key) {
+                        return stringify(key) + ':['
+                            + sources[key][0]
+                            + ',' + stringify(sources[key][1]) + ']'
+                            ;
+                    }).join(',')
+                    + '},{},[' + stringify(skey) + '])'
+                    ;
+
+                var URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
+
+                var blob = new Blob([src], { type: 'text/javascript' });
+                if (options && options.bare) { return blob; }
+                var workerUrl = URL.createObjectURL(blob);
+                var worker = new Worker(workerUrl);
+                worker.objectURL = workerUrl;
+                return worker;
+            };
+
+        }, {}], 5: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+            exports.createDefaultConfig = createDefaultConfig;
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var defaultConfig = exports.defaultConfig = {
+                enableWorker: false,
+                enableStashBuffer: true,
+                stashInitialSize: undefined,
+
+                isLive: false,
+
+                lazyLoad: true,
+                lazyLoadMaxDuration: 3 * 60,
+                lazyLoadRecoverDuration: 30,
+                deferLoadAfterSourceOpen: true,
+
+                // autoCleanupSourceBuffer: default as false, leave unspecified
+                autoCleanupMaxBackwardDuration: 3 * 60,
+                autoCleanupMinBackwardDuration: 2 * 60,
+
+                statisticsInfoReportInterval: 600,
+
+                fixAudioTimestampGap: true,
+
+                accurateSeek: false,
+                seekType: 'range', // [range, param, custom]
+                seekParamStart: 'bstart',
+                seekParamEnd: 'bend',
+                rangeLoadZeroStart: false,
+                customSeekHandler: undefined,
+                reuseRedirectedURL: false,
+                // referrerPolicy: leave as unspecified
+
+                headers: undefined,
+                customLoader: undefined
+            };
+
+            function createDefaultConfig() {
+                return Object.assign({}, defaultConfig);
+            }
+
+        }, {}], 6: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }(); /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
+
+            var _ioController = _dereq_('../io/io-controller.js');
+
+            var _ioController2 = _interopRequireDefault(_ioController);
+
+            var _config = _dereq_('../config.js');
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            var Features = function () {
+                function Features() {
+                    _classCallCheck(this, Features);
                 }
 
-                // if sb is not updating, let's remove ranges now!
-                if (!sb.updating) {
-                    this._doRemoveRanges();
+                _createClass(Features, null, [{
+                    key: 'supportMSEH264Playback',
+                    value: function supportMSEH264Playback() {
+                        return window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');
+                    }
+                }, {
+                    key: 'supportNetworkStreamIO',
+                    value: function supportNetworkStreamIO() {
+                        var ioctl = new _ioController2.default({}, (0, _config.createDefaultConfig)());
+                        var loaderType = ioctl.loaderType;
+                        ioctl.destroy();
+                        return loaderType == 'fetch-stream-loader' || loaderType == 'xhr-moz-chunked-loader';
+                    }
+                }, {
+                    key: 'getNetworkLoaderTypeName',
+                    value: function getNetworkLoaderTypeName() {
+                        var ioctl = new _ioController2.default({}, (0, _config.createDefaultConfig)());
+                        var loaderType = ioctl.loaderType;
+                        ioctl.destroy();
+                        return loaderType;
+                    }
+                }, {
+                    key: 'supportNativeMediaPlayback',
+                    value: function supportNativeMediaPlayback(mimeType) {
+                        if (Features.videoElement == undefined) {
+                            Features.videoElement = window.document.createElement('video');
+                        }
+                        var canPlay = Features.videoElement.canPlayType(mimeType);
+                        return canPlay === 'probably' || canPlay == 'maybe';
+                    }
+                }, {
+                    key: 'getFeatureList',
+                    value: function getFeatureList() {
+                        var features = {
+                            mseFlvPlayback: false,
+                            mseLiveFlvPlayback: false,
+                            networkStreamIO: false,
+                            networkLoaderName: '',
+                            nativeMP4H264Playback: false,
+                            nativeWebmVP8Playback: false,
+                            nativeWebmVP9Playback: false
+                        };
+
+                        features.mseFlvPlayback = Features.supportMSEH264Playback();
+                        features.networkStreamIO = Features.supportNetworkStreamIO();
+                        features.networkLoaderName = Features.getNetworkLoaderTypeName();
+                        features.mseLiveFlvPlayback = features.mseFlvPlayback && features.networkStreamIO;
+                        features.nativeMP4H264Playback = Features.supportNativeMediaPlayback('video/mp4; codecs="avc1.42001E, mp4a.40.2"');
+                        features.nativeWebmVP8Playback = Features.supportNativeMediaPlayback('video/webm; codecs="vp8.0, vorbis"');
+                        features.nativeWebmVP9Playback = Features.supportNativeMediaPlayback('video/webm; codecs="vp9"');
+
+                        return features;
+                    }
+                }]);
+
+                return Features;
+            }();
+
+            exports.default = Features;
+
+        }, { "../config.js": 5, "../io/io-controller.js": 23 }], 7: [function (_dereq_, module, exports) {
+            "use strict";
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }();
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var MediaInfo = function () {
+                function MediaInfo() {
+                    _classCallCheck(this, MediaInfo);
+
+                    this.mimeType = null;
+                    this.duration = null;
+
+                    this.hasAudio = null;
+                    this.hasVideo = null;
+                    this.audioCodec = null;
+                    this.videoCodec = null;
+                    this.audioDataRate = null;
+                    this.videoDataRate = null;
+
+                    this.audioSampleRate = null;
+                    this.audioChannelCount = 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;
+
+                    this.metadata = null;
+                    this.segments = null; // MediaInfo[]
+                    this.segmentCount = null;
+                    this.hasKeyframesIndex = null;
+                    this.keyframesIndex = null;
                 }
 
-                // Safari 10 may get InvalidStateError in the later appendBuffer() after SourceBuffer.remove() call
-                // Internal parser's state may be invalid at this time. Re-append last InitSegment to workaround.
-                // Related issue: https://bugs.webkit.org/show_bug.cgi?id=159230
-                if (_browser2.default.safari) {
-                    var lastInitSegment = this._lastInitSegments[type];
-                    if (lastInitSegment) {
-                        this._pendingSegments[type].push(lastInitSegment);
-                        if (!sb.updating) {
+                _createClass(MediaInfo, [{
+                    key: "isComplete",
+                    value: function isComplete() {
+                        var audioInfoComplete = this.hasAudio === false || this.hasAudio === true && this.audioCodec != null && this.audioSampleRate != null && this.audioChannelCount != null;
+
+                        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;
+
+                        // keyframesIndex may not be present
+                        return this.mimeType != null && this.duration != null && this.metadata != null && this.hasKeyframesIndex != null && audioInfoComplete && videoInfoComplete;
+                    }
+                }, {
+                    key: "isSeekable",
+                    value: function isSeekable() {
+                        return this.hasKeyframesIndex === true;
+                    }
+                }, {
+                    key: "getNearestKeyframe",
+                    value: function getNearestKeyframe(milliseconds) {
+                        if (this.keyframesIndex == null) {
+                            return null;
+                        }
+
+                        var table = this.keyframesIndex;
+                        var keyframeIdx = this._search(table.times, milliseconds);
+
+                        return {
+                            index: keyframeIdx,
+                            milliseconds: table.times[keyframeIdx],
+                            fileposition: table.filepositions[keyframeIdx]
+                        };
+                    }
+                }, {
+                    key: "_search",
+                    value: function _search(list, value) {
+                        var idx = 0;
+
+                        var last = list.length - 1;
+                        var mid = 0;
+                        var lbound = 0;
+                        var ubound = last;
+
+                        if (value < list[0]) {
+                            idx = 0;
+                            lbound = ubound + 1; // skip search
+                        }
+
+                        while (lbound <= ubound) {
+                            mid = lbound + Math.floor((ubound - lbound) / 2);
+                            if (mid === last || value >= list[mid] && value < list[mid + 1]) {
+                                idx = mid;
+                                break;
+                            } else if (list[mid] < value) {
+                                lbound = mid + 1;
+                            } else {
+                                ubound = mid - 1;
+                            }
+                        }
+
+                        return idx;
+                    }
+                }]);
+
+                return MediaInfo;
+            }();
+
+            exports.default = MediaInfo;
+
+        }, {}], 8: [function (_dereq_, module, exports) {
+            "use strict";
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }();
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            // Represents an media sample (audio / video)
+            var SampleInfo = exports.SampleInfo = function SampleInfo(dts, pts, duration, originalDts, isSync) {
+                _classCallCheck(this, SampleInfo);
+
+                this.dts = dts;
+                this.pts = pts;
+                this.duration = duration;
+                this.originalDts = originalDts;
+                this.isSyncPoint = isSync;
+                this.fileposition = null;
+            };
+
+            // Media Segment concept is defined in Media Source Extensions spec.
+            // Particularly in ISO BMFF format, an Media Segment contains a moof box followed by a mdat box.
+
+
+            var MediaSegmentInfo = exports.MediaSegmentInfo = function () {
+                function MediaSegmentInfo() {
+                    _classCallCheck(this, MediaSegmentInfo);
+
+                    this.beginDts = 0;
+                    this.endDts = 0;
+                    this.beginPts = 0;
+                    this.endPts = 0;
+                    this.originalBeginDts = 0;
+                    this.originalEndDts = 0;
+                    this.syncPoints = []; // SampleInfo[n], for video IDR frames only
+                    this.firstSample = null; // SampleInfo
+                    this.lastSample = null; // SampleInfo
+                }
+
+                _createClass(MediaSegmentInfo, [{
+                    key: "appendSyncPoint",
+                    value: function appendSyncPoint(sampleInfo) {
+                        // also called Random Access Point
+                        sampleInfo.isSyncPoint = true;
+                        this.syncPoints.push(sampleInfo);
+                    }
+                }]);
+
+                return MediaSegmentInfo;
+            }();
+
+            // Ordered list for recording video IDR frames, sorted by originalDts
+
+
+            var IDRSampleList = exports.IDRSampleList = function () {
+                function IDRSampleList() {
+                    _classCallCheck(this, IDRSampleList);
+
+                    this._list = [];
+                }
+
+                _createClass(IDRSampleList, [{
+                    key: "clear",
+                    value: function clear() {
+                        this._list = [];
+                    }
+                }, {
+                    key: "appendArray",
+                    value: function appendArray(syncPoints) {
+                        var list = this._list;
+
+                        if (syncPoints.length === 0) {
+                            return;
+                        }
+
+                        if (list.length > 0 && syncPoints[0].originalDts < list[list.length - 1].originalDts) {
+                            this.clear();
+                        }
+
+                        Array.prototype.push.apply(list, syncPoints);
+                    }
+                }, {
+                    key: "getLastSyncPointBeforeDts",
+                    value: function getLastSyncPointBeforeDts(dts) {
+                        if (this._list.length == 0) {
+                            return null;
+                        }
+
+                        var list = this._list;
+                        var idx = 0;
+                        var last = list.length - 1;
+                        var mid = 0;
+                        var lbound = 0;
+                        var ubound = last;
+
+                        if (dts < list[0].dts) {
+                            idx = 0;
+                            lbound = ubound + 1;
+                        }
+
+                        while (lbound <= ubound) {
+                            mid = lbound + Math.floor((ubound - lbound) / 2);
+                            if (mid === last || dts >= list[mid].dts && dts < list[mid + 1].dts) {
+                                idx = mid;
+                                break;
+                            } else if (list[mid].dts < dts) {
+                                lbound = mid + 1;
+                            } else {
+                                ubound = mid - 1;
+                            }
+                        }
+                        return this._list[idx];
+                    }
+                }]);
+
+                return IDRSampleList;
+            }();
+
+            // Data structure for recording information of media segments in single track.
+
+
+            var MediaSegmentInfoList = exports.MediaSegmentInfoList = function () {
+                function MediaSegmentInfoList(type) {
+                    _classCallCheck(this, MediaSegmentInfoList);
+
+                    this._type = type;
+                    this._list = [];
+                    this._lastAppendLocation = -1; // cached last insert location
+                }
+
+                _createClass(MediaSegmentInfoList, [{
+                    key: "isEmpty",
+                    value: function isEmpty() {
+                        return this._list.length === 0;
+                    }
+                }, {
+                    key: "clear",
+                    value: function clear() {
+                        this._list = [];
+                        this._lastAppendLocation = -1;
+                    }
+                }, {
+                    key: "_searchNearestSegmentBefore",
+                    value: function _searchNearestSegmentBefore(originalBeginDts) {
+                        var list = this._list;
+                        if (list.length === 0) {
+                            return -2;
+                        }
+                        var last = list.length - 1;
+                        var mid = 0;
+                        var lbound = 0;
+                        var ubound = last;
+
+                        var idx = 0;
+
+                        if (originalBeginDts < list[0].originalBeginDts) {
+                            idx = -1;
+                            return idx;
+                        }
+
+                        while (lbound <= ubound) {
+                            mid = lbound + Math.floor((ubound - lbound) / 2);
+                            if (mid === last || originalBeginDts > list[mid].lastSample.originalDts && originalBeginDts < list[mid + 1].originalBeginDts) {
+                                idx = mid;
+                                break;
+                            } else if (list[mid].originalBeginDts < originalBeginDts) {
+                                lbound = mid + 1;
+                            } else {
+                                ubound = mid - 1;
+                            }
+                        }
+                        return idx;
+                    }
+                }, {
+                    key: "_searchNearestSegmentAfter",
+                    value: function _searchNearestSegmentAfter(originalBeginDts) {
+                        return this._searchNearestSegmentBefore(originalBeginDts) + 1;
+                    }
+                }, {
+                    key: "append",
+                    value: function append(mediaSegmentInfo) {
+                        var list = this._list;
+                        var msi = mediaSegmentInfo;
+                        var lastAppendIdx = this._lastAppendLocation;
+                        var insertIdx = 0;
+
+                        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)) {
+                            insertIdx = lastAppendIdx + 1; // use cached location idx
+                        } else {
+                            if (list.length > 0) {
+                                insertIdx = this._searchNearestSegmentBefore(msi.originalBeginDts) + 1;
+                            }
+                        }
+
+                        this._lastAppendLocation = insertIdx;
+                        this._list.splice(insertIdx, 0, msi);
+                    }
+                }, {
+                    key: "getLastSegmentBefore",
+                    value: function getLastSegmentBefore(originalBeginDts) {
+                        var idx = this._searchNearestSegmentBefore(originalBeginDts);
+                        if (idx >= 0) {
+                            return this._list[idx];
+                        } else {
+                            // -1
+                            return null;
+                        }
+                    }
+                }, {
+                    key: "getLastSampleBefore",
+                    value: function getLastSampleBefore(originalBeginDts) {
+                        var segment = this.getLastSegmentBefore(originalBeginDts);
+                        if (segment != null) {
+                            return segment.lastSample;
+                        } else {
+                            return null;
+                        }
+                    }
+                }, {
+                    key: "getLastSyncPointBefore",
+                    value: function getLastSyncPointBefore(originalBeginDts) {
+                        var segmentIdx = this._searchNearestSegmentBefore(originalBeginDts);
+                        var syncPoints = this._list[segmentIdx].syncPoints;
+                        while (syncPoints.length === 0 && segmentIdx > 0) {
+                            segmentIdx--;
+                            syncPoints = this._list[segmentIdx].syncPoints;
+                        }
+                        if (syncPoints.length > 0) {
+                            return syncPoints[syncPoints.length - 1];
+                        } else {
+                            return null;
+                        }
+                    }
+                }, {
+                    key: "type",
+                    get: function get() {
+                        return this._type;
+                    }
+                }, {
+                    key: "length",
+                    get: function get() {
+                        return this._list.length;
+                    }
+                }]);
+
+                return MediaSegmentInfoList;
+            }();
+
+        }, {}], 9: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }(); /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
+
+            var _events = _dereq_('events');
+
+            var _events2 = _interopRequireDefault(_events);
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _browser = _dereq_('../utils/browser.js');
+
+            var _browser2 = _interopRequireDefault(_browser);
+
+            var _mseEvents = _dereq_('./mse-events.js');
+
+            var _mseEvents2 = _interopRequireDefault(_mseEvents);
+
+            var _mediaSegmentInfo = _dereq_('./media-segment-info.js');
+
+            var _exception = _dereq_('../utils/exception.js');
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            // Media Source Extensions controller
+            var MSEController = function () {
+                function MSEController(config) {
+                    _classCallCheck(this, MSEController);
+
+                    this.TAG = 'MSEController';
+
+                    this._config = config;
+                    this._emitter = new _events2.default();
+
+                    if (this._config.isLive && this._config.autoCleanupSourceBuffer == undefined) {
+                        // For live stream, do auto cleanup by default
+                        this._config.autoCleanupSourceBuffer = true;
+                    }
+
+                    this.e = {
+                        onSourceOpen: this._onSourceOpen.bind(this),
+                        onSourceEnded: this._onSourceEnded.bind(this),
+                        onSourceClose: this._onSourceClose.bind(this),
+                        onSourceBufferError: this._onSourceBufferError.bind(this),
+                        onSourceBufferUpdateEnd: this._onSourceBufferUpdateEnd.bind(this)
+                    };
+
+                    this._mediaSource = null;
+                    this._mediaSourceObjectURL = null;
+                    this._mediaElement = null;
+
+                    this._isBufferFull = false;
+                    this._hasPendingEos = false;
+
+                    this._requireSetMediaDuration = false;
+                    this._pendingMediaDuration = 0;
+
+                    this._pendingSourceBufferInit = [];
+                    this._mimeTypes = {
+                        video: null,
+                        audio: null
+                    };
+                    this._sourceBuffers = {
+                        video: null,
+                        audio: null
+                    };
+                    this._lastInitSegments = {
+                        video: null,
+                        audio: null
+                    };
+                    this._pendingSegments = {
+                        video: [],
+                        audio: []
+                    };
+                    this._pendingRemoveRanges = {
+                        video: [],
+                        audio: []
+                    };
+                    this._idrList = new _mediaSegmentInfo.IDRSampleList();
+                }
+
+                _createClass(MSEController, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        if (this._mediaElement || this._mediaSource) {
+                            this.detachMediaElement();
+                        }
+                        this.e = null;
+                        this._emitter.removeAllListeners();
+                        this._emitter = null;
+                    }
+                }, {
+                    key: 'on',
+                    value: function on(event, listener) {
+                        this._emitter.addListener(event, listener);
+                    }
+                }, {
+                    key: 'off',
+                    value: function off(event, listener) {
+                        this._emitter.removeListener(event, listener);
+                    }
+                }, {
+                    key: 'attachMediaElement',
+                    value: function attachMediaElement(mediaElement) {
+                        if (this._mediaSource) {
+                            throw new _exception.IllegalStateException('MediaSource has been attached to an HTMLMediaElement!');
+                        }
+                        var ms = this._mediaSource = new window.MediaSource();
+                        ms.addEventListener('sourceopen', this.e.onSourceOpen);
+                        ms.addEventListener('sourceended', this.e.onSourceEnded);
+                        ms.addEventListener('sourceclose', this.e.onSourceClose);
+
+                        this._mediaElement = mediaElement;
+                        this._mediaSourceObjectURL = window.URL.createObjectURL(this._mediaSource);
+                        mediaElement.src = this._mediaSourceObjectURL;
+                    }
+                }, {
+                    key: 'detachMediaElement',
+                    value: function detachMediaElement() {
+                        if (this._mediaSource) {
+                            var ms = this._mediaSource;
+                            for (var type in this._sourceBuffers) {
+                                // pending segments should be discard
+                                var ps = this._pendingSegments[type];
+                                ps.splice(0, ps.length);
+                                this._pendingSegments[type] = null;
+                                this._pendingRemoveRanges[type] = null;
+                                this._lastInitSegments[type] = null;
+
+                                // remove all sourcebuffers
+                                var sb = this._sourceBuffers[type];
+                                if (sb) {
+                                    if (ms.readyState !== 'closed') {
+                                        // ms edge can throw an error: Unexpected call to method or property access
+                                        try {
+                                            ms.removeSourceBuffer(sb);
+                                        } catch (error) {
+                                            _logger2.default.e(this.TAG, error.message);
+                                        }
+                                        sb.removeEventListener('error', this.e.onSourceBufferError);
+                                        sb.removeEventListener('updateend', this.e.onSourceBufferUpdateEnd);
+                                    }
+                                    this._mimeTypes[type] = null;
+                                    this._sourceBuffers[type] = null;
+                                }
+                            }
+                            if (ms.readyState === 'open') {
+                                try {
+                                    ms.endOfStream();
+                                } catch (error) {
+                                    _logger2.default.e(this.TAG, error.message);
+                                }
+                            }
+                            ms.removeEventListener('sourceopen', this.e.onSourceOpen);
+                            ms.removeEventListener('sourceended', this.e.onSourceEnded);
+                            ms.removeEventListener('sourceclose', this.e.onSourceClose);
+                            this._pendingSourceBufferInit = [];
+                            this._isBufferFull = false;
+                            this._idrList.clear();
+                            this._mediaSource = null;
+                        }
+
+                        if (this._mediaElement) {
+                            this._mediaElement.src = '';
+                            this._mediaElement.removeAttribute('src');
+                            this._mediaElement = null;
+                        }
+                        if (this._mediaSourceObjectURL) {
+                            window.URL.revokeObjectURL(this._mediaSourceObjectURL);
+                            this._mediaSourceObjectURL = null;
+                        }
+                    }
+                }, {
+                    key: 'appendInitSegment',
+                    value: function appendInitSegment(initSegment, deferred) {
+                        if (!this._mediaSource || this._mediaSource.readyState !== 'open') {
+                            // sourcebuffer creation requires mediaSource.readyState === 'open'
+                            // so we defer the sourcebuffer creation, until sourceopen event triggered
+                            this._pendingSourceBufferInit.push(initSegment);
+                            // make sure that this InitSegment is in the front of pending segments queue
+                            this._pendingSegments[initSegment.type].push(initSegment);
+                            return;
+                        }
+
+                        var is = initSegment;
+                        var mimeType = '' + is.container;
+                        if (is.codec && is.codec.length > 0) {
+                            mimeType += ';codecs=' + is.codec;
+                        }
+
+                        var firstInitSegment = false;
+
+                        _logger2.default.v(this.TAG, 'Received Initialization Segment, mimeType: ' + mimeType);
+                        this._lastInitSegments[is.type] = is;
+
+                        if (mimeType !== this._mimeTypes[is.type]) {
+                            if (!this._mimeTypes[is.type]) {
+                                // empty, first chance create sourcebuffer
+                                firstInitSegment = true;
+                                try {
+                                    var sb = this._sourceBuffers[is.type] = this._mediaSource.addSourceBuffer(mimeType);
+                                    sb.addEventListener('error', this.e.onSourceBufferError);
+                                    sb.addEventListener('updateend', this.e.onSourceBufferUpdateEnd);
+                                } catch (error) {
+                                    _logger2.default.e(this.TAG, error.message);
+                                    this._emitter.emit(_mseEvents2.default.ERROR, { code: error.code, msg: error.message });
+                                    return;
+                                }
+                            } else {
+                                _logger2.default.v(this.TAG, 'Notice: ' + is.type + ' mimeType changed, origin: ' + this._mimeTypes[is.type] + ', target: ' + mimeType);
+                            }
+                            this._mimeTypes[is.type] = mimeType;
+                        }
+
+                        if (!deferred) {
+                            // deferred means this InitSegment has been pushed to pendingSegments queue
+                            this._pendingSegments[is.type].push(is);
+                        }
+                        if (!firstInitSegment) {
+                            // append immediately only if init segment in subsequence
+                            if (this._sourceBuffers[is.type] && !this._sourceBuffers[is.type].updating) {
+                                this._doAppendSegments();
+                            }
+                        }
+                        if (_browser2.default.safari && is.container === 'audio/mpeg' && is.mediaDuration > 0) {
+                            // 'audio/mpeg' track under Safari may cause MediaElement's duration to be NaN
+                            // Manually correct MediaSource.duration to make progress bar seekable, and report right duration
+                            this._requireSetMediaDuration = true;
+                            this._pendingMediaDuration = is.mediaDuration / 1000; // in seconds
+                            this._updateMediaSourceDuration();
+                        }
+                    }
+                }, {
+                    key: 'appendMediaSegment',
+                    value: function appendMediaSegment(mediaSegment) {
+                        var ms = mediaSegment;
+                        this._pendingSegments[ms.type].push(ms);
+
+                        if (this._config.autoCleanupSourceBuffer && this._needCleanupSourceBuffer()) {
+                            this._doCleanupSourceBuffer();
+                        }
+
+                        var sb = this._sourceBuffers[ms.type];
+                        if (sb && !sb.updating && !this._hasPendingRemoveRanges()) {
                             this._doAppendSegments();
                         }
                     }
-                }
-            }
-        }
-    }, {
-        key: 'endOfStream',
-        value: function endOfStream() {
-            var ms = this._mediaSource;
-            var sb = this._sourceBuffers;
-            if (!ms || ms.readyState !== 'open') {
-                if (ms && ms.readyState === 'closed' && this._hasPendingSegments()) {
-                    // If MediaSource hasn't turned into open state, and there're pending segments
-                    // Mark pending endOfStream, defer call until all pending segments appended complete
-                    this._hasPendingEos = true;
-                }
-                return;
-            }
-            if (sb.video && sb.video.updating || sb.audio && sb.audio.updating) {
-                // If any sourcebuffer is updating, defer endOfStream operation
-                // See _onSourceBufferUpdateEnd()
-                this._hasPendingEos = true;
-            } else {
-                this._hasPendingEos = false;
-                // Notify media data loading complete
-                // This is helpful for correcting total duration to match last media segment
-                // Otherwise MediaElement's ended event may not be triggered
-                ms.endOfStream();
-            }
-        }
-    }, {
-        key: 'getNearestKeyframe',
-        value: function getNearestKeyframe(dts) {
-            return this._idrList.getLastSyncPointBeforeDts(dts);
-        }
-    }, {
-        key: '_needCleanupSourceBuffer',
-        value: function _needCleanupSourceBuffer() {
-            if (!this._config.autoCleanupSourceBuffer) {
-                return false;
-            }
-
-            var currentTime = this._mediaElement.currentTime;
-
-            for (var type in this._sourceBuffers) {
-                var sb = this._sourceBuffers[type];
-                if (sb) {
-                    var buffered = sb.buffered;
-                    if (buffered.length >= 1) {
-                        if (currentTime - buffered.start(0) >= this._config.autoCleanupMaxBackwardDuration) {
-                            return true;
-                        }
-                    }
-                }
-            }
-
-            return false;
-        }
-    }, {
-        key: '_doCleanupSourceBuffer',
-        value: function _doCleanupSourceBuffer() {
-            var currentTime = this._mediaElement.currentTime;
-
-            for (var type in this._sourceBuffers) {
-                var sb = this._sourceBuffers[type];
-                if (sb) {
-                    var buffered = sb.buffered;
-                    var doRemove = false;
-
-                    for (var i = 0; i < buffered.length; i++) {
-                        var start = buffered.start(i);
-                        var end = buffered.end(i);
-
-                        if (start <= currentTime && currentTime < end + 3) {
-                            // padding 3 seconds
-                            if (currentTime - start >= this._config.autoCleanupMaxBackwardDuration) {
-                                doRemove = true;
-                                var removeEnd = currentTime - this._config.autoCleanupMinBackwardDuration;
-                                this._pendingRemoveRanges[type].push({ start: start, end: removeEnd });
+                }, {
+                    key: 'seek',
+                    value: function seek(seconds) {
+                        // remove all appended buffers
+                        for (var type in this._sourceBuffers) {
+                            if (!this._sourceBuffers[type]) {
+                                continue;
                             }
-                        } else if (end < currentTime) {
-                            doRemove = true;
-                            this._pendingRemoveRanges[type].push({ start: start, end: end });
-                        }
-                    }
 
-                    if (doRemove && !sb.updating) {
-                        this._doRemoveRanges();
-                    }
-                }
-            }
-        }
-    }, {
-        key: '_updateMediaSourceDuration',
-        value: function _updateMediaSourceDuration() {
-            var sb = this._sourceBuffers;
-            if (this._mediaElement.readyState === 0 || this._mediaSource.readyState !== 'open') {
-                return;
-            }
-            if (sb.video && sb.video.updating || sb.audio && sb.audio.updating) {
-                return;
-            }
-
-            var current = this._mediaSource.duration;
-            var target = this._pendingMediaDuration;
-
-            if (target > 0 && (isNaN(current) || target > current)) {
-                _logger2.default.v(this.TAG, 'Update MediaSource duration from ' + current + ' to ' + target);
-                this._mediaSource.duration = target;
-            }
-
-            this._requireSetMediaDuration = false;
-            this._pendingMediaDuration = 0;
-        }
-    }, {
-        key: '_doRemoveRanges',
-        value: function _doRemoveRanges() {
-            for (var type in this._pendingRemoveRanges) {
-                if (!this._sourceBuffers[type] || this._sourceBuffers[type].updating) {
-                    continue;
-                }
-                var sb = this._sourceBuffers[type];
-                var ranges = this._pendingRemoveRanges[type];
-                while (ranges.length && !sb.updating) {
-                    var range = ranges.shift();
-                    sb.remove(range.start, range.end);
-                }
-            }
-        }
-    }, {
-        key: '_doAppendSegments',
-        value: function _doAppendSegments() {
-            var pendingSegments = this._pendingSegments;
-
-            for (var type in pendingSegments) {
-                if (!this._sourceBuffers[type] || this._sourceBuffers[type].updating) {
-                    continue;
-                }
-
-                if (pendingSegments[type].length > 0) {
-                    var segment = pendingSegments[type].shift();
-
-                    if (segment.timestampOffset) {
-                        // For MPEG audio stream in MSE, if unbuffered-seeking occurred
-                        // We need explicitly set timestampOffset to the desired point in timeline for mpeg SourceBuffer.
-                        var currentOffset = this._sourceBuffers[type].timestampOffset;
-                        var targetOffset = segment.timestampOffset / 1000; // in seconds
-
-                        var delta = Math.abs(currentOffset - targetOffset);
-                        if (delta > 0.1) {
-                            // If time delta > 100ms
-                            _logger2.default.v(this.TAG, 'Update MPEG audio timestampOffset from ' + currentOffset + ' to ' + targetOffset);
-                            this._sourceBuffers[type].timestampOffset = targetOffset;
-                        }
-                        delete segment.timestampOffset;
-                    }
-
-                    if (!segment.data || segment.data.byteLength === 0) {
-                        // Ignore empty buffer
-                        continue;
-                    }
-
-                    try {
-                        this._sourceBuffers[type].appendBuffer(segment.data);
-                        this._isBufferFull = false;
-                        if (type === 'video' && segment.hasOwnProperty('info')) {
-                            this._idrList.appendArray(segment.info.syncPoints);
-                        }
-                    } catch (error) {
-                        this._pendingSegments[type].unshift(segment);
-                        if (error.code === 22) {
-                            // QuotaExceededError
-                            /* Notice that FireFox may not throw QuotaExceededError if SourceBuffer is full
-                             * Currently we can only do lazy-load to avoid SourceBuffer become scattered.
-                             * SourceBuffer eviction policy may be changed in future version of FireFox.
-                             *
-                             * Related issues:
-                             * https://bugzilla.mozilla.org/show_bug.cgi?id=1279885
-                             * https://bugzilla.mozilla.org/show_bug.cgi?id=1280023
-                             */
-
-                            // report buffer full, abort network IO
-                            if (!this._isBufferFull) {
-                                this._emitter.emit(_mseEvents2.default.BUFFER_FULL);
+                            // abort current buffer append algorithm
+                            var sb = this._sourceBuffers[type];
+                            if (this._mediaSource.readyState === 'open') {
+                                try {
+                                    // If range removal algorithm is running, InvalidStateError will be throwed
+                                    // Ignore it.
+                                    sb.abort();
+                                } catch (error) {
+                                    _logger2.default.e(this.TAG, error.message);
+                                }
                             }
-                            this._isBufferFull = true;
+
+                            // IDRList should be clear
+                            this._idrList.clear();
+
+                            // pending segments should be discard
+                            var ps = this._pendingSegments[type];
+                            ps.splice(0, ps.length);
+
+                            if (this._mediaSource.readyState === 'closed') {
+                                // Parent MediaSource object has been detached from HTMLMediaElement
+                                continue;
+                            }
+
+                            // record ranges to be remove from SourceBuffer
+                            for (var i = 0; i < sb.buffered.length; i++) {
+                                var start = sb.buffered.start(i);
+                                var end = sb.buffered.end(i);
+                                this._pendingRemoveRanges[type].push({ start: start, end: end });
+                            }
+
+                            // if sb is not updating, let's remove ranges now!
+                            if (!sb.updating) {
+                                this._doRemoveRanges();
+                            }
+
+                            // Safari 10 may get InvalidStateError in the later appendBuffer() after SourceBuffer.remove() call
+                            // Internal parser's state may be invalid at this time. Re-append last InitSegment to workaround.
+                            // Related issue: https://bugs.webkit.org/show_bug.cgi?id=159230
+                            if (_browser2.default.safari) {
+                                var lastInitSegment = this._lastInitSegments[type];
+                                if (lastInitSegment) {
+                                    this._pendingSegments[type].push(lastInitSegment);
+                                    if (!sb.updating) {
+                                        this._doAppendSegments();
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }, {
+                    key: 'endOfStream',
+                    value: function endOfStream() {
+                        var ms = this._mediaSource;
+                        var sb = this._sourceBuffers;
+                        if (!ms || ms.readyState !== 'open') {
+                            if (ms && ms.readyState === 'closed' && this._hasPendingSegments()) {
+                                // If MediaSource hasn't turned into open state, and there're pending segments
+                                // Mark pending endOfStream, defer call until all pending segments appended complete
+                                this._hasPendingEos = true;
+                            }
+                            return;
+                        }
+                        if (sb.video && sb.video.updating || sb.audio && sb.audio.updating) {
+                            // If any sourcebuffer is updating, defer endOfStream operation
+                            // See _onSourceBufferUpdateEnd()
+                            this._hasPendingEos = true;
                         } else {
-                            _logger2.default.e(this.TAG, error.message);
-                            this._emitter.emit(_mseEvents2.default.ERROR, { code: error.code, msg: error.message });
+                            this._hasPendingEos = false;
+                            // Notify media data loading complete
+                            // This is helpful for correcting total duration to match last media segment
+                            // Otherwise MediaElement's ended event may not be triggered
+                            ms.endOfStream();
                         }
                     }
-                }
-            }
-        }
-    }, {
-        key: '_onSourceOpen',
-        value: function _onSourceOpen() {
-            _logger2.default.v(this.TAG, 'MediaSource onSourceOpen');
-            this._mediaSource.removeEventListener('sourceopen', this.e.onSourceOpen);
-            // deferred sourcebuffer creation / initialization
-            if (this._pendingSourceBufferInit.length > 0) {
-                var pendings = this._pendingSourceBufferInit;
-                while (pendings.length) {
-                    var segment = pendings.shift();
-                    this.appendInitSegment(segment, true);
-                }
-            }
-            // there may be some pending media segments, append them
-            if (this._hasPendingSegments()) {
-                this._doAppendSegments();
-            }
-            this._emitter.emit(_mseEvents2.default.SOURCE_OPEN);
-        }
-    }, {
-        key: '_onSourceEnded',
-        value: function _onSourceEnded() {
-            // fired on endOfStream
-            _logger2.default.v(this.TAG, 'MediaSource onSourceEnded');
-        }
-    }, {
-        key: '_onSourceClose',
-        value: function _onSourceClose() {
-            // fired on detaching from media element
-            _logger2.default.v(this.TAG, 'MediaSource onSourceClose');
-            if (this._mediaSource && this.e != null) {
-                this._mediaSource.removeEventListener('sourceopen', this.e.onSourceOpen);
-                this._mediaSource.removeEventListener('sourceended', this.e.onSourceEnded);
-                this._mediaSource.removeEventListener('sourceclose', this.e.onSourceClose);
-            }
-        }
-    }, {
-        key: '_hasPendingSegments',
-        value: function _hasPendingSegments() {
-            var ps = this._pendingSegments;
-            return ps.video.length > 0 || ps.audio.length > 0;
-        }
-    }, {
-        key: '_hasPendingRemoveRanges',
-        value: function _hasPendingRemoveRanges() {
-            var prr = this._pendingRemoveRanges;
-            return prr.video.length > 0 || prr.audio.length > 0;
-        }
-    }, {
-        key: '_onSourceBufferUpdateEnd',
-        value: function _onSourceBufferUpdateEnd() {
-            if (this._requireSetMediaDuration) {
-                this._updateMediaSourceDuration();
-            } else if (this._hasPendingRemoveRanges()) {
-                this._doRemoveRanges();
-            } else if (this._hasPendingSegments()) {
-                this._doAppendSegments();
-            } else if (this._hasPendingEos) {
-                this.endOfStream();
-            }
-            this._emitter.emit(_mseEvents2.default.UPDATE_END);
-        }
-    }, {
-        key: '_onSourceBufferError',
-        value: function _onSourceBufferError(e) {
-            _logger2.default.e(this.TAG, 'SourceBuffer Error: ' + e);
-            // this error might not always be fatal, just ignore it
-        }
-    }]);
-
-    return MSEController;
-}();
-
-exports.default = MSEController;
-
-},{"../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){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var MSEEvents = {
-  ERROR: 'error',
-  SOURCE_OPEN: 'source_open',
-  UPDATE_END: 'update_end',
-  BUFFER_FULL: 'buffer_full'
-};
-
-exports.default = MSEEvents;
-
-},{}],11:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
-
-var _events = _dereq_('events');
-
-var _events2 = _interopRequireDefault(_events);
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _loggingControl = _dereq_('../utils/logging-control.js');
-
-var _loggingControl2 = _interopRequireDefault(_loggingControl);
-
-var _transmuxingController = _dereq_('./transmuxing-controller.js');
-
-var _transmuxingController2 = _interopRequireDefault(_transmuxingController);
-
-var _transmuxingEvents = _dereq_('./transmuxing-events.js');
-
-var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
-
-var _transmuxingWorker = _dereq_('./transmuxing-worker.js');
-
-var _transmuxingWorker2 = _interopRequireDefault(_transmuxingWorker);
-
-var _mediaInfo = _dereq_('./media-info.js');
-
-var _mediaInfo2 = _interopRequireDefault(_mediaInfo);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-var Transmuxer = function () {
-    function Transmuxer(mediaDataSource, config) {
-        _classCallCheck(this, Transmuxer);
-
-        this.TAG = 'Transmuxer';
-        this._emitter = new _events2.default();
-
-        if (config.enableWorker && typeof Worker !== 'undefined') {
-            try {
-                var work = _dereq_('webworkify');
-                this._worker = work(_transmuxingWorker2.default);
-                this._workerDestroying = false;
-                this._worker.addEventListener('message', this._onWorkerMessage.bind(this));
-                this._worker.postMessage({ cmd: 'init', param: [mediaDataSource, config] });
-                this.e = {
-                    onLoggingConfigChanged: this._onLoggingConfigChanged.bind(this)
-                };
-                _loggingControl2.default.registerListener(this.e.onLoggingConfigChanged);
-                this._worker.postMessage({ cmd: 'logging_config', param: _loggingControl2.default.getConfig() });
-            } catch (error) {
-                _logger2.default.e(this.TAG, 'Error while initialize transmuxing worker, fallback to inline transmuxing');
-                this._worker = null;
-                this._controller = new _transmuxingController2.default(mediaDataSource, config);
-            }
-        } else {
-            this._controller = new _transmuxingController2.default(mediaDataSource, config);
-        }
-
-        if (this._controller) {
-            var ctl = this._controller;
-            ctl.on(_transmuxingEvents2.default.IO_ERROR, this._onIOError.bind(this));
-            ctl.on(_transmuxingEvents2.default.DEMUX_ERROR, this._onDemuxError.bind(this));
-            ctl.on(_transmuxingEvents2.default.INIT_SEGMENT, this._onInitSegment.bind(this));
-            ctl.on(_transmuxingEvents2.default.MEDIA_SEGMENT, this._onMediaSegment.bind(this));
-            ctl.on(_transmuxingEvents2.default.LOADING_COMPLETE, this._onLoadingComplete.bind(this));
-            ctl.on(_transmuxingEvents2.default.RECOVERED_EARLY_EOF, this._onRecoveredEarlyEof.bind(this));
-            ctl.on(_transmuxingEvents2.default.MEDIA_INFO, this._onMediaInfo.bind(this));
-            ctl.on(_transmuxingEvents2.default.METADATA_ARRIVED, this._onMetaDataArrived.bind(this));
-            ctl.on(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, this._onScriptDataArrived.bind(this));
-            ctl.on(_transmuxingEvents2.default.STATISTICS_INFO, this._onStatisticsInfo.bind(this));
-            ctl.on(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, this._onRecommendSeekpoint.bind(this));
-        }
-    }
-
-    _createClass(Transmuxer, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this._worker) {
-                if (!this._workerDestroying) {
-                    this._workerDestroying = true;
-                    this._worker.postMessage({ cmd: 'destroy' });
-                    _loggingControl2.default.removeListener(this.e.onLoggingConfigChanged);
-                    this.e = null;
-                }
-            } else {
-                this._controller.destroy();
-                this._controller = null;
-            }
-            this._emitter.removeAllListeners();
-            this._emitter = null;
-        }
-    }, {
-        key: 'on',
-        value: function on(event, listener) {
-            this._emitter.addListener(event, listener);
-        }
-    }, {
-        key: 'off',
-        value: function off(event, listener) {
-            this._emitter.removeListener(event, listener);
-        }
-    }, {
-        key: 'hasWorker',
-        value: function hasWorker() {
-            return this._worker != null;
-        }
-    }, {
-        key: 'open',
-        value: function open() {
-            if (this._worker) {
-                this._worker.postMessage({ cmd: 'start' });
-            } else {
-                this._controller.start();
-            }
-        }
-    }, {
-        key: 'close',
-        value: function close() {
-            if (this._worker) {
-                this._worker.postMessage({ cmd: 'stop' });
-            } else {
-                this._controller.stop();
-            }
-        }
-    }, {
-        key: 'seek',
-        value: function seek(milliseconds) {
-            if (this._worker) {
-                this._worker.postMessage({ cmd: 'seek', param: milliseconds });
-            } else {
-                this._controller.seek(milliseconds);
-            }
-        }
-    }, {
-        key: 'pause',
-        value: function pause() {
-            if (this._worker) {
-                this._worker.postMessage({ cmd: 'pause' });
-            } else {
-                this._controller.pause();
-            }
-        }
-    }, {
-        key: 'resume',
-        value: function resume() {
-            if (this._worker) {
-                this._worker.postMessage({ cmd: 'resume' });
-            } else {
-                this._controller.resume();
-            }
-        }
-    }, {
-        key: '_onInitSegment',
-        value: function _onInitSegment(type, initSegment) {
-            var _this = this;
-
-            // do async invoke
-            Promise.resolve().then(function () {
-                _this._emitter.emit(_transmuxingEvents2.default.INIT_SEGMENT, type, initSegment);
-            });
-        }
-    }, {
-        key: '_onMediaSegment',
-        value: function _onMediaSegment(type, mediaSegment) {
-            var _this2 = this;
-
-            Promise.resolve().then(function () {
-                _this2._emitter.emit(_transmuxingEvents2.default.MEDIA_SEGMENT, type, mediaSegment);
-            });
-        }
-    }, {
-        key: '_onLoadingComplete',
-        value: function _onLoadingComplete() {
-            var _this3 = this;
-
-            Promise.resolve().then(function () {
-                _this3._emitter.emit(_transmuxingEvents2.default.LOADING_COMPLETE);
-            });
-        }
-    }, {
-        key: '_onRecoveredEarlyEof',
-        value: function _onRecoveredEarlyEof() {
-            var _this4 = this;
-
-            Promise.resolve().then(function () {
-                _this4._emitter.emit(_transmuxingEvents2.default.RECOVERED_EARLY_EOF);
-            });
-        }
-    }, {
-        key: '_onMediaInfo',
-        value: function _onMediaInfo(mediaInfo) {
-            var _this5 = this;
-
-            Promise.resolve().then(function () {
-                _this5._emitter.emit(_transmuxingEvents2.default.MEDIA_INFO, mediaInfo);
-            });
-        }
-    }, {
-        key: '_onMetaDataArrived',
-        value: function _onMetaDataArrived(metadata) {
-            var _this6 = this;
-
-            Promise.resolve().then(function () {
-                _this6._emitter.emit(_transmuxingEvents2.default.METADATA_ARRIVED, metadata);
-            });
-        }
-    }, {
-        key: '_onScriptDataArrived',
-        value: function _onScriptDataArrived(data) {
-            var _this7 = this;
-
-            Promise.resolve().then(function () {
-                _this7._emitter.emit(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, data);
-            });
-        }
-    }, {
-        key: '_onStatisticsInfo',
-        value: function _onStatisticsInfo(statisticsInfo) {
-            var _this8 = this;
-
-            Promise.resolve().then(function () {
-                _this8._emitter.emit(_transmuxingEvents2.default.STATISTICS_INFO, statisticsInfo);
-            });
-        }
-    }, {
-        key: '_onIOError',
-        value: function _onIOError(type, info) {
-            var _this9 = this;
-
-            Promise.resolve().then(function () {
-                _this9._emitter.emit(_transmuxingEvents2.default.IO_ERROR, type, info);
-            });
-        }
-    }, {
-        key: '_onDemuxError',
-        value: function _onDemuxError(type, info) {
-            var _this10 = this;
-
-            Promise.resolve().then(function () {
-                _this10._emitter.emit(_transmuxingEvents2.default.DEMUX_ERROR, type, info);
-            });
-        }
-    }, {
-        key: '_onRecommendSeekpoint',
-        value: function _onRecommendSeekpoint(milliseconds) {
-            var _this11 = this;
-
-            Promise.resolve().then(function () {
-                _this11._emitter.emit(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, milliseconds);
-            });
-        }
-    }, {
-        key: '_onLoggingConfigChanged',
-        value: function _onLoggingConfigChanged(config) {
-            if (this._worker) {
-                this._worker.postMessage({ cmd: 'logging_config', param: config });
-            }
-        }
-    }, {
-        key: '_onWorkerMessage',
-        value: function _onWorkerMessage(e) {
-            var message = e.data;
-            var data = message.data;
-
-            if (message.msg === 'destroyed' || this._workerDestroying) {
-                this._workerDestroying = false;
-                this._worker.terminate();
-                this._worker = null;
-                return;
-            }
-
-            switch (message.msg) {
-                case _transmuxingEvents2.default.INIT_SEGMENT:
-                case _transmuxingEvents2.default.MEDIA_SEGMENT:
-                    this._emitter.emit(message.msg, data.type, data.data);
-                    break;
-                case _transmuxingEvents2.default.LOADING_COMPLETE:
-                case _transmuxingEvents2.default.RECOVERED_EARLY_EOF:
-                    this._emitter.emit(message.msg);
-                    break;
-                case _transmuxingEvents2.default.MEDIA_INFO:
-                    Object.setPrototypeOf(data, _mediaInfo2.default.prototype);
-                    this._emitter.emit(message.msg, data);
-                    break;
-                case _transmuxingEvents2.default.METADATA_ARRIVED:
-                case _transmuxingEvents2.default.SCRIPTDATA_ARRIVED:
-                case _transmuxingEvents2.default.STATISTICS_INFO:
-                    this._emitter.emit(message.msg, data);
-                    break;
-                case _transmuxingEvents2.default.IO_ERROR:
-                case _transmuxingEvents2.default.DEMUX_ERROR:
-                    this._emitter.emit(message.msg, data.type, data.info);
-                    break;
-                case _transmuxingEvents2.default.RECOMMEND_SEEKPOINT:
-                    this._emitter.emit(message.msg, data);
-                    break;
-                case 'logcat_callback':
-                    _logger2.default.emitter.emit('log', data.type, data.logcat);
-                    break;
-                default:
-                    break;
-            }
-        }
-    }]);
-
-    return Transmuxer;
-}();
-
-exports.default = Transmuxer;
-
-},{"../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){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
-
-var _events = _dereq_('events');
-
-var _events2 = _interopRequireDefault(_events);
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _browser = _dereq_('../utils/browser.js');
-
-var _browser2 = _interopRequireDefault(_browser);
-
-var _mediaInfo = _dereq_('./media-info.js');
-
-var _mediaInfo2 = _interopRequireDefault(_mediaInfo);
-
-var _flvDemuxer = _dereq_('../demux/flv-demuxer.js');
-
-var _flvDemuxer2 = _interopRequireDefault(_flvDemuxer);
-
-var _mp4Remuxer = _dereq_('../remux/mp4-remuxer.js');
-
-var _mp4Remuxer2 = _interopRequireDefault(_mp4Remuxer);
-
-var _demuxErrors = _dereq_('../demux/demux-errors.js');
-
-var _demuxErrors2 = _interopRequireDefault(_demuxErrors);
-
-var _ioController = _dereq_('../io/io-controller.js');
-
-var _ioController2 = _interopRequireDefault(_ioController);
-
-var _transmuxingEvents = _dereq_('./transmuxing-events.js');
-
-var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
-
-var _loader = _dereq_('../io/loader.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-// Transmuxing (IO, Demuxing, Remuxing) controller, with multipart support
-var TransmuxingController = function () {
-    function TransmuxingController(mediaDataSource, config) {
-        _classCallCheck(this, TransmuxingController);
-
-        this.TAG = 'TransmuxingController';
-        this._emitter = new _events2.default();
-
-        this._config = config;
-
-        // treat single part media as multipart media, which has only one segment
-        if (!mediaDataSource.segments) {
-            mediaDataSource.segments = [{
-                duration: mediaDataSource.duration,
-                filesize: mediaDataSource.filesize,
-                url: mediaDataSource.url
-            }];
-        }
-
-        // fill in default IO params if not exists
-        if (typeof mediaDataSource.cors !== 'boolean') {
-            mediaDataSource.cors = true;
-        }
-        if (typeof mediaDataSource.withCredentials !== 'boolean') {
-            mediaDataSource.withCredentials = false;
-        }
-
-        this._mediaDataSource = mediaDataSource;
-        this._currentSegmentIndex = 0;
-        var totalDuration = 0;
-
-        this._mediaDataSource.segments.forEach(function (segment) {
-            // timestampBase for each segment, and calculate total duration
-            segment.timestampBase = totalDuration;
-            totalDuration += segment.duration;
-            // params needed by IOController
-            segment.cors = mediaDataSource.cors;
-            segment.withCredentials = mediaDataSource.withCredentials;
-            // referrer policy control, if exist
-            if (config.referrerPolicy) {
-                segment.referrerPolicy = config.referrerPolicy;
-            }
-        });
-
-        if (!isNaN(totalDuration) && this._mediaDataSource.duration !== totalDuration) {
-            this._mediaDataSource.duration = totalDuration;
-        }
-
-        this._mediaInfo = null;
-        this._demuxer = null;
-        this._remuxer = null;
-        this._ioctl = null;
-
-        this._pendingSeekTime = null;
-        this._pendingResolveSeekPoint = null;
-
-        this._statisticsReporter = null;
-    }
-
-    _createClass(TransmuxingController, [{
-        key: 'destroy',
-        value: function destroy() {
-            this._mediaInfo = null;
-            this._mediaDataSource = null;
-
-            if (this._statisticsReporter) {
-                this._disableStatisticsReporter();
-            }
-            if (this._ioctl) {
-                this._ioctl.destroy();
-                this._ioctl = null;
-            }
-            if (this._demuxer) {
-                this._demuxer.destroy();
-                this._demuxer = null;
-            }
-            if (this._remuxer) {
-                this._remuxer.destroy();
-                this._remuxer = null;
-            }
-
-            this._emitter.removeAllListeners();
-            this._emitter = null;
-        }
-    }, {
-        key: 'on',
-        value: function on(event, listener) {
-            this._emitter.addListener(event, listener);
-        }
-    }, {
-        key: 'off',
-        value: function off(event, listener) {
-            this._emitter.removeListener(event, listener);
-        }
-    }, {
-        key: 'start',
-        value: function start() {
-            this._loadSegment(0);
-            this._enableStatisticsReporter();
-        }
-    }, {
-        key: '_loadSegment',
-        value: function _loadSegment(segmentIndex, optionalFrom) {
-            this._currentSegmentIndex = segmentIndex;
-            var dataSource = this._mediaDataSource.segments[segmentIndex];
-
-            var ioctl = this._ioctl = new _ioController2.default(dataSource, this._config, segmentIndex);
-            ioctl.onError = this._onIOException.bind(this);
-            ioctl.onSeeked = this._onIOSeeked.bind(this);
-            ioctl.onComplete = this._onIOComplete.bind(this);
-            ioctl.onRedirect = this._onIORedirect.bind(this);
-            ioctl.onRecoveredEarlyEof = this._onIORecoveredEarlyEof.bind(this);
-
-            if (optionalFrom) {
-                this._demuxer.bindDataSource(this._ioctl);
-            } else {
-                ioctl.onDataArrival = this._onInitChunkArrival.bind(this);
-            }
-
-            ioctl.open(optionalFrom);
-        }
-    }, {
-        key: 'stop',
-        value: function stop() {
-            this._internalAbort();
-            this._disableStatisticsReporter();
-        }
-    }, {
-        key: '_internalAbort',
-        value: function _internalAbort() {
-            if (this._ioctl) {
-                this._ioctl.destroy();
-                this._ioctl = null;
-            }
-        }
-    }, {
-        key: 'pause',
-        value: function pause() {
-            // take a rest
-            if (this._ioctl && this._ioctl.isWorking()) {
-                this._ioctl.pause();
-                this._disableStatisticsReporter();
-            }
-        }
-    }, {
-        key: 'resume',
-        value: function resume() {
-            if (this._ioctl && this._ioctl.isPaused()) {
-                this._ioctl.resume();
-                this._enableStatisticsReporter();
-            }
-        }
-    }, {
-        key: 'seek',
-        value: function seek(milliseconds) {
-            if (this._mediaInfo == null || !this._mediaInfo.isSeekable()) {
-                return;
-            }
-
-            var targetSegmentIndex = this._searchSegmentIndexContains(milliseconds);
-
-            if (targetSegmentIndex === this._currentSegmentIndex) {
-                // intra-segment seeking
-                var segmentInfo = this._mediaInfo.segments[targetSegmentIndex];
-
-                if (segmentInfo == undefined) {
-                    // current segment loading started, but mediainfo hasn't received yet
-                    // wait for the metadata loaded, then seek to expected position
-                    this._pendingSeekTime = milliseconds;
-                } else {
-                    var keyframe = segmentInfo.getNearestKeyframe(milliseconds);
-                    this._remuxer.seek(keyframe.milliseconds);
-                    this._ioctl.seek(keyframe.fileposition);
-                    // Will be resolved in _onRemuxerMediaSegmentArrival()
-                    this._pendingResolveSeekPoint = keyframe.milliseconds;
-                }
-            } else {
-                // cross-segment seeking
-                var targetSegmentInfo = this._mediaInfo.segments[targetSegmentIndex];
-
-                if (targetSegmentInfo == undefined) {
-                    // target segment hasn't been loaded. We need metadata then seek to expected time
-                    this._pendingSeekTime = milliseconds;
-                    this._internalAbort();
-                    this._remuxer.seek();
-                    this._remuxer.insertDiscontinuity();
-                    this._loadSegment(targetSegmentIndex);
-                    // Here we wait for the metadata loaded, then seek to expected position
-                } else {
-                    // We have target segment's metadata, direct seek to target position
-                    var _keyframe = targetSegmentInfo.getNearestKeyframe(milliseconds);
-                    this._internalAbort();
-                    this._remuxer.seek(milliseconds);
-                    this._remuxer.insertDiscontinuity();
-                    this._demuxer.resetMediaInfo();
-                    this._demuxer.timestampBase = this._mediaDataSource.segments[targetSegmentIndex].timestampBase;
-                    this._loadSegment(targetSegmentIndex, _keyframe.fileposition);
-                    this._pendingResolveSeekPoint = _keyframe.milliseconds;
-                    this._reportSegmentMediaInfo(targetSegmentIndex);
-                }
-            }
-
-            this._enableStatisticsReporter();
-        }
-    }, {
-        key: '_searchSegmentIndexContains',
-        value: function _searchSegmentIndexContains(milliseconds) {
-            var segments = this._mediaDataSource.segments;
-            var idx = segments.length - 1;
-
-            for (var i = 0; i < segments.length; i++) {
-                if (milliseconds < segments[i].timestampBase) {
-                    idx = i - 1;
-                    break;
-                }
-            }
-            return idx;
-        }
-    }, {
-        key: '_onInitChunkArrival',
-        value: function _onInitChunkArrival(data, byteStart) {
-            var _this = this;
-
-            var probeData = null;
-            var consumed = 0;
-
-            if (byteStart > 0) {
-                // IOController seeked immediately after opened, byteStart > 0 callback may received
-                this._demuxer.bindDataSource(this._ioctl);
-                this._demuxer.timestampBase = this._mediaDataSource.segments[this._currentSegmentIndex].timestampBase;
-
-                consumed = this._demuxer.parseChunks(data, byteStart);
-            } else if ((probeData = _flvDemuxer2.default.probe(data)).match) {
-                // Always create new FLVDemuxer
-                this._demuxer = new _flvDemuxer2.default(probeData, this._config);
-
-                if (!this._remuxer) {
-                    this._remuxer = new _mp4Remuxer2.default(this._config);
-                }
-
-                var mds = this._mediaDataSource;
-                if (mds.duration != undefined && !isNaN(mds.duration)) {
-                    this._demuxer.overridedDuration = mds.duration;
-                }
-                if (typeof mds.hasAudio === 'boolean') {
-                    this._demuxer.overridedHasAudio = mds.hasAudio;
-                }
-                if (typeof mds.hasVideo === 'boolean') {
-                    this._demuxer.overridedHasVideo = mds.hasVideo;
-                }
-
-                this._demuxer.timestampBase = mds.segments[this._currentSegmentIndex].timestampBase;
-
-                this._demuxer.onError = this._onDemuxException.bind(this);
-                this._demuxer.onMediaInfo = this._onMediaInfo.bind(this);
-                this._demuxer.onMetaDataArrived = this._onMetaDataArrived.bind(this);
-                this._demuxer.onScriptDataArrived = this._onScriptDataArrived.bind(this);
-
-                this._remuxer.bindDataSource(this._demuxer.bindDataSource(this._ioctl));
-
-                this._remuxer.onInitSegment = this._onRemuxerInitSegmentArrival.bind(this);
-                this._remuxer.onMediaSegment = this._onRemuxerMediaSegmentArrival.bind(this);
-
-                consumed = this._demuxer.parseChunks(data, byteStart);
-            } else {
-                probeData = null;
-                _logger2.default.e(this.TAG, 'Non-FLV, Unsupported media type!');
-                Promise.resolve().then(function () {
-                    _this._internalAbort();
-                });
-                this._emitter.emit(_transmuxingEvents2.default.DEMUX_ERROR, _demuxErrors2.default.FORMAT_UNSUPPORTED, 'Non-FLV, Unsupported media type');
-
-                consumed = 0;
-            }
-
-            return consumed;
-        }
-    }, {
-        key: '_onMediaInfo',
-        value: function _onMediaInfo(mediaInfo) {
-            var _this2 = this;
-
-            if (this._mediaInfo == null) {
-                // Store first segment's mediainfo as global mediaInfo
-                this._mediaInfo = Object.assign({}, mediaInfo);
-                this._mediaInfo.keyframesIndex = null;
-                this._mediaInfo.segments = [];
-                this._mediaInfo.segmentCount = this._mediaDataSource.segments.length;
-                Object.setPrototypeOf(this._mediaInfo, _mediaInfo2.default.prototype);
-            }
-
-            var segmentInfo = Object.assign({}, mediaInfo);
-            Object.setPrototypeOf(segmentInfo, _mediaInfo2.default.prototype);
-            this._mediaInfo.segments[this._currentSegmentIndex] = segmentInfo;
-
-            // notify mediaInfo update
-            this._reportSegmentMediaInfo(this._currentSegmentIndex);
-
-            if (this._pendingSeekTime != null) {
-                Promise.resolve().then(function () {
-                    var target = _this2._pendingSeekTime;
-                    _this2._pendingSeekTime = null;
-                    _this2.seek(target);
-                });
-            }
-        }
-    }, {
-        key: '_onMetaDataArrived',
-        value: function _onMetaDataArrived(metadata) {
-            this._emitter.emit(_transmuxingEvents2.default.METADATA_ARRIVED, metadata);
-        }
-    }, {
-        key: '_onScriptDataArrived',
-        value: function _onScriptDataArrived(data) {
-            this._emitter.emit(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, data);
-        }
-    }, {
-        key: '_onIOSeeked',
-        value: function _onIOSeeked() {
-            this._remuxer.insertDiscontinuity();
-        }
-    }, {
-        key: '_onIOComplete',
-        value: function _onIOComplete(extraData) {
-            var segmentIndex = extraData;
-            var nextSegmentIndex = segmentIndex + 1;
-
-            if (nextSegmentIndex < this._mediaDataSource.segments.length) {
-                this._internalAbort();
-                this._remuxer.flushStashedSamples();
-                this._loadSegment(nextSegmentIndex);
-            } else {
-                this._remuxer.flushStashedSamples();
-                this._emitter.emit(_transmuxingEvents2.default.LOADING_COMPLETE);
-                this._disableStatisticsReporter();
-            }
-        }
-    }, {
-        key: '_onIORedirect',
-        value: function _onIORedirect(redirectedURL) {
-            var segmentIndex = this._ioctl.extraData;
-            this._mediaDataSource.segments[segmentIndex].redirectedURL = redirectedURL;
-        }
-    }, {
-        key: '_onIORecoveredEarlyEof',
-        value: function _onIORecoveredEarlyEof() {
-            this._emitter.emit(_transmuxingEvents2.default.RECOVERED_EARLY_EOF);
-        }
-    }, {
-        key: '_onIOException',
-        value: function _onIOException(type, info) {
-            _logger2.default.e(this.TAG, 'IOException: type = ' + type + ', code = ' + info.code + ', msg = ' + info.msg);
-            this._emitter.emit(_transmuxingEvents2.default.IO_ERROR, type, info);
-            this._disableStatisticsReporter();
-        }
-    }, {
-        key: '_onDemuxException',
-        value: function _onDemuxException(type, info) {
-            _logger2.default.e(this.TAG, 'DemuxException: type = ' + type + ', info = ' + info);
-            this._emitter.emit(_transmuxingEvents2.default.DEMUX_ERROR, type, info);
-        }
-    }, {
-        key: '_onRemuxerInitSegmentArrival',
-        value: function _onRemuxerInitSegmentArrival(type, initSegment) {
-            this._emitter.emit(_transmuxingEvents2.default.INIT_SEGMENT, type, initSegment);
-        }
-    }, {
-        key: '_onRemuxerMediaSegmentArrival',
-        value: function _onRemuxerMediaSegmentArrival(type, mediaSegment) {
-            if (this._pendingSeekTime != null) {
-                // Media segments after new-segment cross-seeking should be dropped.
-                return;
-            }
-            this._emitter.emit(_transmuxingEvents2.default.MEDIA_SEGMENT, type, mediaSegment);
-
-            // Resolve pending seekPoint
-            if (this._pendingResolveSeekPoint != null && type === 'video') {
-                var syncPoints = mediaSegment.info.syncPoints;
-                var seekpoint = this._pendingResolveSeekPoint;
-                this._pendingResolveSeekPoint = null;
-
-                // Safari: Pass PTS for recommend_seekpoint
-                if (_browser2.default.safari && syncPoints.length > 0 && syncPoints[0].originalDts === seekpoint) {
-                    seekpoint = syncPoints[0].pts;
-                }
-                // else: use original DTS (keyframe.milliseconds)
-
-                this._emitter.emit(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, seekpoint);
-            }
-        }
-    }, {
-        key: '_enableStatisticsReporter',
-        value: function _enableStatisticsReporter() {
-            if (this._statisticsReporter == null) {
-                this._statisticsReporter = self.setInterval(this._reportStatisticsInfo.bind(this), this._config.statisticsInfoReportInterval);
-            }
-        }
-    }, {
-        key: '_disableStatisticsReporter',
-        value: function _disableStatisticsReporter() {
-            if (this._statisticsReporter) {
-                self.clearInterval(this._statisticsReporter);
-                this._statisticsReporter = null;
-            }
-        }
-    }, {
-        key: '_reportSegmentMediaInfo',
-        value: function _reportSegmentMediaInfo(segmentIndex) {
-            var segmentInfo = this._mediaInfo.segments[segmentIndex];
-            var exportInfo = Object.assign({}, segmentInfo);
-
-            exportInfo.duration = this._mediaInfo.duration;
-            exportInfo.segmentCount = this._mediaInfo.segmentCount;
-            delete exportInfo.segments;
-            delete exportInfo.keyframesIndex;
-
-            this._emitter.emit(_transmuxingEvents2.default.MEDIA_INFO, exportInfo);
-        }
-    }, {
-        key: '_reportStatisticsInfo',
-        value: function _reportStatisticsInfo() {
-            var info = {};
-
-            info.url = this._ioctl.currentURL;
-            info.hasRedirect = this._ioctl.hasRedirect;
-            if (info.hasRedirect) {
-                info.redirectedURL = this._ioctl.currentRedirectedURL;
-            }
-
-            info.speed = this._ioctl.currentSpeed;
-            info.loaderType = this._ioctl.loaderType;
-            info.currentSegmentIndex = this._currentSegmentIndex;
-            info.totalSegmentCount = this._mediaDataSource.segments.length;
-
-            this._emitter.emit(_transmuxingEvents2.default.STATISTICS_INFO, info);
-        }
-    }]);
-
-    return TransmuxingController;
-}();
-
-exports.default = TransmuxingController;
-
-},{"../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){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var TransmuxingEvents = {
-  IO_ERROR: 'io_error',
-  DEMUX_ERROR: 'demux_error',
-  INIT_SEGMENT: 'init_segment',
-  MEDIA_SEGMENT: 'media_segment',
-  LOADING_COMPLETE: 'loading_complete',
-  RECOVERED_EARLY_EOF: 'recovered_early_eof',
-  MEDIA_INFO: 'media_info',
-  METADATA_ARRIVED: 'metadata_arrived',
-  SCRIPTDATA_ARRIVED: 'scriptdata_arrived',
-  STATISTICS_INFO: 'statistics_info',
-  RECOMMEND_SEEKPOINT: 'recommend_seekpoint'
-};
-
-exports.default = TransmuxingEvents;
-
-},{}],14:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _loggingControl = _dereq_('../utils/logging-control.js');
-
-var _loggingControl2 = _interopRequireDefault(_loggingControl);
-
-var _polyfill = _dereq_('../utils/polyfill.js');
-
-var _polyfill2 = _interopRequireDefault(_polyfill);
-
-var _transmuxingController = _dereq_('./transmuxing-controller.js');
-
-var _transmuxingController2 = _interopRequireDefault(_transmuxingController);
-
-var _transmuxingEvents = _dereq_('./transmuxing-events.js');
-
-var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/* post message to worker:
-   data: {
-       cmd: string
-       param: any
-   }
-
-   receive message from worker:
-   data: {
-       msg: string,
-       data: any
-   }
- */
-
-var TransmuxingWorker = function TransmuxingWorker(self) {
-
-    var TAG = 'TransmuxingWorker';
-    var controller = null;
-    var logcatListener = onLogcatCallback.bind(this);
-
-    _polyfill2.default.install();
-
-    self.addEventListener('message', function (e) {
-        switch (e.data.cmd) {
-            case 'init':
-                controller = new _transmuxingController2.default(e.data.param[0], e.data.param[1]);
-                controller.on(_transmuxingEvents2.default.IO_ERROR, onIOError.bind(this));
-                controller.on(_transmuxingEvents2.default.DEMUX_ERROR, onDemuxError.bind(this));
-                controller.on(_transmuxingEvents2.default.INIT_SEGMENT, onInitSegment.bind(this));
-                controller.on(_transmuxingEvents2.default.MEDIA_SEGMENT, onMediaSegment.bind(this));
-                controller.on(_transmuxingEvents2.default.LOADING_COMPLETE, onLoadingComplete.bind(this));
-                controller.on(_transmuxingEvents2.default.RECOVERED_EARLY_EOF, onRecoveredEarlyEof.bind(this));
-                controller.on(_transmuxingEvents2.default.MEDIA_INFO, onMediaInfo.bind(this));
-                controller.on(_transmuxingEvents2.default.METADATA_ARRIVED, onMetaDataArrived.bind(this));
-                controller.on(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, onScriptDataArrived.bind(this));
-                controller.on(_transmuxingEvents2.default.STATISTICS_INFO, onStatisticsInfo.bind(this));
-                controller.on(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, onRecommendSeekpoint.bind(this));
-                break;
-            case 'destroy':
-                if (controller) {
-                    controller.destroy();
-                    controller = null;
-                }
-                self.postMessage({ msg: 'destroyed' });
-                break;
-            case 'start':
-                controller.start();
-                break;
-            case 'stop':
-                controller.stop();
-                break;
-            case 'seek':
-                controller.seek(e.data.param);
-                break;
-            case 'pause':
-                controller.pause();
-                break;
-            case 'resume':
-                controller.resume();
-                break;
-            case 'logging_config':
-                {
-                    var config = e.data.param;
-                    _loggingControl2.default.applyConfig(config);
-
-                    if (config.enableCallback === true) {
-                        _loggingControl2.default.addLogListener(logcatListener);
-                    } else {
-                        _loggingControl2.default.removeLogListener(logcatListener);
+                }, {
+                    key: 'getNearestKeyframe',
+                    value: function getNearestKeyframe(dts) {
+                        return this._idrList.getLastSyncPointBeforeDts(dts);
                     }
-                    break;
+                }, {
+                    key: '_needCleanupSourceBuffer',
+                    value: function _needCleanupSourceBuffer() {
+                        if (!this._config.autoCleanupSourceBuffer) {
+                            return false;
+                        }
+
+                        var currentTime = this._mediaElement.currentTime;
+
+                        for (var type in this._sourceBuffers) {
+                            var sb = this._sourceBuffers[type];
+                            if (sb) {
+                                var buffered = sb.buffered;
+                                if (buffered.length >= 1) {
+                                    if (currentTime - buffered.start(0) >= this._config.autoCleanupMaxBackwardDuration) {
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+
+                        return false;
+                    }
+                }, {
+                    key: '_doCleanupSourceBuffer',
+                    value: function _doCleanupSourceBuffer() {
+                        var currentTime = this._mediaElement.currentTime;
+
+                        for (var type in this._sourceBuffers) {
+                            var sb = this._sourceBuffers[type];
+                            if (sb) {
+                                var buffered = sb.buffered;
+                                var doRemove = false;
+
+                                for (var i = 0; i < buffered.length; i++) {
+                                    var start = buffered.start(i);
+                                    var end = buffered.end(i);
+
+                                    if (start <= currentTime && currentTime < end + 3) {
+                                        // padding 3 seconds
+                                        if (currentTime - start >= this._config.autoCleanupMaxBackwardDuration) {
+                                            doRemove = true;
+                                            var removeEnd = currentTime - this._config.autoCleanupMinBackwardDuration;
+                                            this._pendingRemoveRanges[type].push({ start: start, end: removeEnd });
+                                        }
+                                    } else if (end < currentTime) {
+                                        doRemove = true;
+                                        this._pendingRemoveRanges[type].push({ start: start, end: end });
+                                    }
+                                }
+
+                                if (doRemove && !sb.updating) {
+                                    this._doRemoveRanges();
+                                }
+                            }
+                        }
+                    }
+                }, {
+                    key: '_updateMediaSourceDuration',
+                    value: function _updateMediaSourceDuration() {
+                        var sb = this._sourceBuffers;
+                        if (this._mediaElement.readyState === 0 || this._mediaSource.readyState !== 'open') {
+                            return;
+                        }
+                        if (sb.video && sb.video.updating || sb.audio && sb.audio.updating) {
+                            return;
+                        }
+
+                        var current = this._mediaSource.duration;
+                        var target = this._pendingMediaDuration;
+
+                        if (target > 0 && (isNaN(current) || target > current)) {
+                            _logger2.default.v(this.TAG, 'Update MediaSource duration from ' + current + ' to ' + target);
+                            this._mediaSource.duration = target;
+                        }
+
+                        this._requireSetMediaDuration = false;
+                        this._pendingMediaDuration = 0;
+                    }
+                }, {
+                    key: '_doRemoveRanges',
+                    value: function _doRemoveRanges() {
+                        for (var type in this._pendingRemoveRanges) {
+                            if (!this._sourceBuffers[type] || this._sourceBuffers[type].updating) {
+                                continue;
+                            }
+                            var sb = this._sourceBuffers[type];
+                            var ranges = this._pendingRemoveRanges[type];
+                            while (ranges.length && !sb.updating) {
+                                var range = ranges.shift();
+                                sb.remove(range.start, range.end);
+                            }
+                        }
+                    }
+                }, {
+                    key: '_doAppendSegments',
+                    value: function _doAppendSegments() {
+                        var pendingSegments = this._pendingSegments;
+
+                        for (var type in pendingSegments) {
+                            if (!this._sourceBuffers[type] || this._sourceBuffers[type].updating) {
+                                continue;
+                            }
+
+                            if (pendingSegments[type].length > 0) {
+                                var segment = pendingSegments[type].shift();
+
+                                if (segment.timestampOffset) {
+                                    // For MPEG audio stream in MSE, if unbuffered-seeking occurred
+                                    // We need explicitly set timestampOffset to the desired point in timeline for mpeg SourceBuffer.
+                                    var currentOffset = this._sourceBuffers[type].timestampOffset;
+                                    var targetOffset = segment.timestampOffset / 1000; // in seconds
+
+                                    var delta = Math.abs(currentOffset - targetOffset);
+                                    if (delta > 0.1) {
+                                        // If time delta > 100ms
+                                        _logger2.default.v(this.TAG, 'Update MPEG audio timestampOffset from ' + currentOffset + ' to ' + targetOffset);
+                                        this._sourceBuffers[type].timestampOffset = targetOffset;
+                                    }
+                                    delete segment.timestampOffset;
+                                }
+
+                                if (!segment.data || segment.data.byteLength === 0) {
+                                    // Ignore empty buffer
+                                    continue;
+                                }
+
+                                try {
+                                    this._sourceBuffers[type].appendBuffer(segment.data);
+                                    this._isBufferFull = false;
+                                    if (type === 'video' && segment.hasOwnProperty('info')) {
+                                        this._idrList.appendArray(segment.info.syncPoints);
+                                    }
+                                } catch (error) {
+                                    this._pendingSegments[type].unshift(segment);
+                                    if (error.code === 22) {
+                                        // QuotaExceededError
+                                        /* Notice that FireFox may not throw QuotaExceededError if SourceBuffer is full
+                                         * Currently we can only do lazy-load to avoid SourceBuffer become scattered.
+                                         * SourceBuffer eviction policy may be changed in future version of FireFox.
+                                         *
+                                         * Related issues:
+                                         * https://bugzilla.mozilla.org/show_bug.cgi?id=1279885
+                                         * https://bugzilla.mozilla.org/show_bug.cgi?id=1280023
+                                         */
+
+                                        // report buffer full, abort network IO
+                                        if (!this._isBufferFull) {
+                                            this._emitter.emit(_mseEvents2.default.BUFFER_FULL);
+                                        }
+                                        this._isBufferFull = true;
+                                    } else {
+                                        _logger2.default.e(this.TAG, error.message);
+                                        this._emitter.emit(_mseEvents2.default.ERROR, { code: error.code, msg: error.message });
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }, {
+                    key: '_onSourceOpen',
+                    value: function _onSourceOpen() {
+                        _logger2.default.v(this.TAG, 'MediaSource onSourceOpen');
+                        this._mediaSource.removeEventListener('sourceopen', this.e.onSourceOpen);
+                        // deferred sourcebuffer creation / initialization
+                        if (this._pendingSourceBufferInit.length > 0) {
+                            var pendings = this._pendingSourceBufferInit;
+                            while (pendings.length) {
+                                var segment = pendings.shift();
+                                this.appendInitSegment(segment, true);
+                            }
+                        }
+                        // there may be some pending media segments, append them
+                        if (this._hasPendingSegments()) {
+                            this._doAppendSegments();
+                        }
+                        this._emitter.emit(_mseEvents2.default.SOURCE_OPEN);
+                    }
+                }, {
+                    key: '_onSourceEnded',
+                    value: function _onSourceEnded() {
+                        // fired on endOfStream
+                        _logger2.default.v(this.TAG, 'MediaSource onSourceEnded');
+                    }
+                }, {
+                    key: '_onSourceClose',
+                    value: function _onSourceClose() {
+                        // fired on detaching from media element
+                        _logger2.default.v(this.TAG, 'MediaSource onSourceClose');
+                        if (this._mediaSource && this.e != null) {
+                            this._mediaSource.removeEventListener('sourceopen', this.e.onSourceOpen);
+                            this._mediaSource.removeEventListener('sourceended', this.e.onSourceEnded);
+                            this._mediaSource.removeEventListener('sourceclose', this.e.onSourceClose);
+                        }
+                    }
+                }, {
+                    key: '_hasPendingSegments',
+                    value: function _hasPendingSegments() {
+                        var ps = this._pendingSegments;
+                        return ps.video.length > 0 || ps.audio.length > 0;
+                    }
+                }, {
+                    key: '_hasPendingRemoveRanges',
+                    value: function _hasPendingRemoveRanges() {
+                        var prr = this._pendingRemoveRanges;
+                        return prr.video.length > 0 || prr.audio.length > 0;
+                    }
+                }, {
+                    key: '_onSourceBufferUpdateEnd',
+                    value: function _onSourceBufferUpdateEnd() {
+                        if (this._requireSetMediaDuration) {
+                            this._updateMediaSourceDuration();
+                        } else if (this._hasPendingRemoveRanges()) {
+                            this._doRemoveRanges();
+                        } else if (this._hasPendingSegments()) {
+                            this._doAppendSegments();
+                        } else if (this._hasPendingEos) {
+                            this.endOfStream();
+                        }
+                        this._emitter.emit(_mseEvents2.default.UPDATE_END);
+                    }
+                }, {
+                    key: '_onSourceBufferError',
+                    value: function _onSourceBufferError(e) {
+                        _logger2.default.e(this.TAG, 'SourceBuffer Error: ' + e);
+                        // this error might not always be fatal, just ignore it
+                    }
+                }]);
+
+                return MSEController;
+            }();
+
+            exports.default = MSEController;
+
+        }, { "../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) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var MSEEvents = {
+                ERROR: 'error',
+                SOURCE_OPEN: 'source_open',
+                UPDATE_END: 'update_end',
+                BUFFER_FULL: 'buffer_full'
+            };
+
+            exports.default = MSEEvents;
+
+        }, {}], 11: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }(); /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
+
+            var _events = _dereq_('events');
+
+            var _events2 = _interopRequireDefault(_events);
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _loggingControl = _dereq_('../utils/logging-control.js');
+
+            var _loggingControl2 = _interopRequireDefault(_loggingControl);
+
+            var _transmuxingController = _dereq_('./transmuxing-controller.js');
+
+            var _transmuxingController2 = _interopRequireDefault(_transmuxingController);
+
+            var _transmuxingEvents = _dereq_('./transmuxing-events.js');
+
+            var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
+
+            var _transmuxingWorker = _dereq_('./transmuxing-worker.js');
+
+            var _transmuxingWorker2 = _interopRequireDefault(_transmuxingWorker);
+
+            var _mediaInfo = _dereq_('./media-info.js');
+
+            var _mediaInfo2 = _interopRequireDefault(_mediaInfo);
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            var Transmuxer = function () {
+                function Transmuxer(mediaDataSource, config) {
+                    _classCallCheck(this, Transmuxer);
+
+                    this.TAG = 'Transmuxer';
+                    this._emitter = new _events2.default();
+
+                    if (config.enableWorker && typeof Worker !== 'undefined') {
+                        try {
+                            var work = _dereq_('webworkify');
+                            this._worker = work(_transmuxingWorker2.default);
+                            this._workerDestroying = false;
+                            this._worker.addEventListener('message', this._onWorkerMessage.bind(this));
+                            this._worker.postMessage({ cmd: 'init', param: [mediaDataSource, config] });
+                            this.e = {
+                                onLoggingConfigChanged: this._onLoggingConfigChanged.bind(this)
+                            };
+                            _loggingControl2.default.registerListener(this.e.onLoggingConfigChanged);
+                            this._worker.postMessage({ cmd: 'logging_config', param: _loggingControl2.default.getConfig() });
+                        } catch (error) {
+                            _logger2.default.e(this.TAG, 'Error while initialize transmuxing worker, fallback to inline transmuxing');
+                            this._worker = null;
+                            this._controller = new _transmuxingController2.default(mediaDataSource, config);
+                        }
+                    } else {
+                        this._controller = new _transmuxingController2.default(mediaDataSource, config);
+                    }
+
+                    if (this._controller) {
+                        var ctl = this._controller;
+                        ctl.on(_transmuxingEvents2.default.IO_ERROR, this._onIOError.bind(this));
+                        ctl.on(_transmuxingEvents2.default.DEMUX_ERROR, this._onDemuxError.bind(this));
+                        ctl.on(_transmuxingEvents2.default.INIT_SEGMENT, this._onInitSegment.bind(this));
+                        ctl.on(_transmuxingEvents2.default.MEDIA_SEGMENT, this._onMediaSegment.bind(this));
+                        ctl.on(_transmuxingEvents2.default.LOADING_COMPLETE, this._onLoadingComplete.bind(this));
+                        ctl.on(_transmuxingEvents2.default.RECOVERED_EARLY_EOF, this._onRecoveredEarlyEof.bind(this));
+                        ctl.on(_transmuxingEvents2.default.MEDIA_INFO, this._onMediaInfo.bind(this));
+                        ctl.on(_transmuxingEvents2.default.METADATA_ARRIVED, this._onMetaDataArrived.bind(this));
+                        ctl.on(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, this._onScriptDataArrived.bind(this));
+                        ctl.on(_transmuxingEvents2.default.STATISTICS_INFO, this._onStatisticsInfo.bind(this));
+                        ctl.on(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, this._onRecommendSeekpoint.bind(this));
+                    }
                 }
-        }
-    });
 
-    function onInitSegment(type, initSegment) {
-        var obj = {
-            msg: _transmuxingEvents2.default.INIT_SEGMENT,
-            data: {
-                type: type,
-                data: initSegment
-            }
-        };
-        self.postMessage(obj, [initSegment.data]); // data: ArrayBuffer
-    }
+                _createClass(Transmuxer, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        if (this._worker) {
+                            if (!this._workerDestroying) {
+                                this._workerDestroying = true;
+                                this._worker.postMessage({ cmd: 'destroy' });
+                                _loggingControl2.default.removeListener(this.e.onLoggingConfigChanged);
+                                this.e = null;
+                            }
+                        } else {
+                            this._controller.destroy();
+                            this._controller = null;
+                        }
+                        this._emitter.removeAllListeners();
+                        this._emitter = null;
+                    }
+                }, {
+                    key: 'on',
+                    value: function on(event, listener) {
+                        this._emitter.addListener(event, listener);
+                    }
+                }, {
+                    key: 'off',
+                    value: function off(event, listener) {
+                        this._emitter.removeListener(event, listener);
+                    }
+                }, {
+                    key: 'hasWorker',
+                    value: function hasWorker() {
+                        return this._worker != null;
+                    }
+                }, {
+                    key: 'open',
+                    value: function open() {
+                        if (this._worker) {
+                            this._worker.postMessage({ cmd: 'start' });
+                        } else {
+                            this._controller.start();
+                        }
+                    }
+                }, {
+                    key: 'close',
+                    value: function close() {
+                        if (this._worker) {
+                            this._worker.postMessage({ cmd: 'stop' });
+                        } else {
+                            this._controller.stop();
+                        }
+                    }
+                }, {
+                    key: 'seek',
+                    value: function seek(milliseconds) {
+                        if (this._worker) {
+                            this._worker.postMessage({ cmd: 'seek', param: milliseconds });
+                        } else {
+                            this._controller.seek(milliseconds);
+                        }
+                    }
+                }, {
+                    key: 'pause',
+                    value: function pause() {
+                        if (this._worker) {
+                            this._worker.postMessage({ cmd: 'pause' });
+                        } else {
+                            this._controller.pause();
+                        }
+                    }
+                }, {
+                    key: 'resume',
+                    value: function resume() {
+                        if (this._worker) {
+                            this._worker.postMessage({ cmd: 'resume' });
+                        } else {
+                            this._controller.resume();
+                        }
+                    }
+                }, {
+                    key: '_onInitSegment',
+                    value: function _onInitSegment(type, initSegment) {
+                        var _this = this;
 
-    function onMediaSegment(type, mediaSegment) {
-        var obj = {
-            msg: _transmuxingEvents2.default.MEDIA_SEGMENT,
-            data: {
-                type: type,
-                data: mediaSegment
-            }
-        };
-        self.postMessage(obj, [mediaSegment.data]); // data: ArrayBuffer
-    }
+                        // do async invoke
+                        Promise.resolve().then(function () {
+                            _this._emitter.emit(_transmuxingEvents2.default.INIT_SEGMENT, type, initSegment);
+                        });
+                    }
+                }, {
+                    key: '_onMediaSegment',
+                    value: function _onMediaSegment(type, mediaSegment) {
+                        var _this2 = this;
 
-    function onLoadingComplete() {
-        var obj = {
-            msg: _transmuxingEvents2.default.LOADING_COMPLETE
-        };
-        self.postMessage(obj);
-    }
+                        Promise.resolve().then(function () {
+                            _this2._emitter.emit(_transmuxingEvents2.default.MEDIA_SEGMENT, type, mediaSegment);
+                        });
+                    }
+                }, {
+                    key: '_onLoadingComplete',
+                    value: function _onLoadingComplete() {
+                        var _this3 = this;
 
-    function onRecoveredEarlyEof() {
-        var obj = {
-            msg: _transmuxingEvents2.default.RECOVERED_EARLY_EOF
-        };
-        self.postMessage(obj);
-    }
+                        Promise.resolve().then(function () {
+                            _this3._emitter.emit(_transmuxingEvents2.default.LOADING_COMPLETE);
+                        });
+                    }
+                }, {
+                    key: '_onRecoveredEarlyEof',
+                    value: function _onRecoveredEarlyEof() {
+                        var _this4 = this;
 
-    function onMediaInfo(mediaInfo) {
-        var obj = {
-            msg: _transmuxingEvents2.default.MEDIA_INFO,
-            data: mediaInfo
-        };
-        self.postMessage(obj);
-    }
+                        Promise.resolve().then(function () {
+                            _this4._emitter.emit(_transmuxingEvents2.default.RECOVERED_EARLY_EOF);
+                        });
+                    }
+                }, {
+                    key: '_onMediaInfo',
+                    value: function _onMediaInfo(mediaInfo) {
+                        var _this5 = this;
 
-    function onMetaDataArrived(metadata) {
-        var obj = {
-            msg: _transmuxingEvents2.default.METADATA_ARRIVED,
-            data: metadata
-        };
-        self.postMessage(obj);
-    }
+                        Promise.resolve().then(function () {
+                            _this5._emitter.emit(_transmuxingEvents2.default.MEDIA_INFO, mediaInfo);
+                        });
+                    }
+                }, {
+                    key: '_onMetaDataArrived',
+                    value: function _onMetaDataArrived(metadata) {
+                        var _this6 = this;
 
-    function onScriptDataArrived(data) {
-        var obj = {
-            msg: _transmuxingEvents2.default.SCRIPTDATA_ARRIVED,
-            data: data
-        };
-        self.postMessage(obj);
-    }
+                        Promise.resolve().then(function () {
+                            _this6._emitter.emit(_transmuxingEvents2.default.METADATA_ARRIVED, metadata);
+                        });
+                    }
+                }, {
+                    key: '_onScriptDataArrived',
+                    value: function _onScriptDataArrived(data) {
+                        var _this7 = this;
 
-    function onStatisticsInfo(statInfo) {
-        var obj = {
-            msg: _transmuxingEvents2.default.STATISTICS_INFO,
-            data: statInfo
-        };
-        self.postMessage(obj);
-    }
+                        Promise.resolve().then(function () {
+                            _this7._emitter.emit(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, data);
+                        });
+                    }
+                }, {
+                    key: '_onStatisticsInfo',
+                    value: function _onStatisticsInfo(statisticsInfo) {
+                        var _this8 = this;
 
-    function onIOError(type, info) {
-        self.postMessage({
-            msg: _transmuxingEvents2.default.IO_ERROR,
-            data: {
-                type: type,
-                info: info
-            }
-        });
-    }
+                        Promise.resolve().then(function () {
+                            _this8._emitter.emit(_transmuxingEvents2.default.STATISTICS_INFO, statisticsInfo);
+                        });
+                    }
+                }, {
+                    key: '_onIOError',
+                    value: function _onIOError(type, info) {
+                        var _this9 = this;
 
-    function onDemuxError(type, info) {
-        self.postMessage({
-            msg: _transmuxingEvents2.default.DEMUX_ERROR,
-            data: {
-                type: type,
-                info: info
-            }
-        });
-    }
+                        Promise.resolve().then(function () {
+                            _this9._emitter.emit(_transmuxingEvents2.default.IO_ERROR, type, info);
+                        });
+                    }
+                }, {
+                    key: '_onDemuxError',
+                    value: function _onDemuxError(type, info) {
+                        var _this10 = this;
 
-    function onRecommendSeekpoint(milliseconds) {
-        self.postMessage({
-            msg: _transmuxingEvents2.default.RECOMMEND_SEEKPOINT,
-            data: milliseconds
-        });
-    }
+                        Promise.resolve().then(function () {
+                            _this10._emitter.emit(_transmuxingEvents2.default.DEMUX_ERROR, type, info);
+                        });
+                    }
+                }, {
+                    key: '_onRecommendSeekpoint',
+                    value: function _onRecommendSeekpoint(milliseconds) {
+                        var _this11 = this;
 
-    function onLogcatCallback(type, str) {
-        self.postMessage({
-            msg: 'logcat_callback',
-            data: {
-                type: type,
-                logcat: str
-            }
-        });
-    }
-}; /*
+                        Promise.resolve().then(function () {
+                            _this11._emitter.emit(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, milliseconds);
+                        });
+                    }
+                }, {
+                    key: '_onLoggingConfigChanged',
+                    value: function _onLoggingConfigChanged(config) {
+                        if (this._worker) {
+                            this._worker.postMessage({ cmd: 'logging_config', param: config });
+                        }
+                    }
+                }, {
+                    key: '_onWorkerMessage',
+                    value: function _onWorkerMessage(e) {
+                        var message = e.data;
+                        var data = message.data;
+
+                        if (message.msg === 'destroyed' || this._workerDestroying) {
+                            this._workerDestroying = false;
+                            this._worker.terminate();
+                            this._worker = null;
+                            return;
+                        }
+
+                        switch (message.msg) {
+                            case _transmuxingEvents2.default.INIT_SEGMENT:
+                            case _transmuxingEvents2.default.MEDIA_SEGMENT:
+                                this._emitter.emit(message.msg, data.type, data.data);
+                                break;
+                            case _transmuxingEvents2.default.LOADING_COMPLETE:
+                            case _transmuxingEvents2.default.RECOVERED_EARLY_EOF:
+                                this._emitter.emit(message.msg);
+                                break;
+                            case _transmuxingEvents2.default.MEDIA_INFO:
+                                Object.setPrototypeOf(data, _mediaInfo2.default.prototype);
+                                this._emitter.emit(message.msg, data);
+                                break;
+                            case _transmuxingEvents2.default.METADATA_ARRIVED:
+                            case _transmuxingEvents2.default.SCRIPTDATA_ARRIVED:
+                            case _transmuxingEvents2.default.STATISTICS_INFO:
+                                this._emitter.emit(message.msg, data);
+                                break;
+                            case _transmuxingEvents2.default.IO_ERROR:
+                            case _transmuxingEvents2.default.DEMUX_ERROR:
+                                this._emitter.emit(message.msg, data.type, data.info);
+                                break;
+                            case _transmuxingEvents2.default.RECOMMEND_SEEKPOINT:
+                                this._emitter.emit(message.msg, data);
+                                break;
+                            case 'logcat_callback':
+                                _logger2.default.emitter.emit('log', data.type, data.logcat);
+                                break;
+                            default:
+                                break;
+                        }
+                    }
+                }]);
+
+                return Transmuxer;
+            }();
+
+            exports.default = Transmuxer;
+
+        }, { "../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) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }(); /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
+
+            var _events = _dereq_('events');
+
+            var _events2 = _interopRequireDefault(_events);
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _browser = _dereq_('../utils/browser.js');
+
+            var _browser2 = _interopRequireDefault(_browser);
+
+            var _mediaInfo = _dereq_('./media-info.js');
+
+            var _mediaInfo2 = _interopRequireDefault(_mediaInfo);
+
+            var _flvDemuxer = _dereq_('../demux/flv-demuxer.js');
+
+            var _flvDemuxer2 = _interopRequireDefault(_flvDemuxer);
+
+            var _mp4Remuxer = _dereq_('../remux/mp4-remuxer.js');
+
+            var _mp4Remuxer2 = _interopRequireDefault(_mp4Remuxer);
+
+            var _demuxErrors = _dereq_('../demux/demux-errors.js');
+
+            var _demuxErrors2 = _interopRequireDefault(_demuxErrors);
+
+            var _ioController = _dereq_('../io/io-controller.js');
+
+            var _ioController2 = _interopRequireDefault(_ioController);
+
+            var _transmuxingEvents = _dereq_('./transmuxing-events.js');
+
+            var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
+
+            var _loader = _dereq_('../io/loader.js');
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            // Transmuxing (IO, Demuxing, Remuxing) controller, with multipart support
+            var TransmuxingController = function () {
+                function TransmuxingController(mediaDataSource, config) {
+                    _classCallCheck(this, TransmuxingController);
+
+                    this.TAG = 'TransmuxingController';
+                    this._emitter = new _events2.default();
+
+                    this._config = config;
+
+                    // treat single part media as multipart media, which has only one segment
+                    if (!mediaDataSource.segments) {
+                        mediaDataSource.segments = [{
+                            duration: mediaDataSource.duration,
+                            filesize: mediaDataSource.filesize,
+                            url: mediaDataSource.url
+                        }];
+                    }
+
+                    // fill in default IO params if not exists
+                    if (typeof mediaDataSource.cors !== 'boolean') {
+                        mediaDataSource.cors = true;
+                    }
+                    if (typeof mediaDataSource.withCredentials !== 'boolean') {
+                        mediaDataSource.withCredentials = false;
+                    }
+
+                    this._mediaDataSource = mediaDataSource;
+                    this._currentSegmentIndex = 0;
+                    var totalDuration = 0;
+
+                    this._mediaDataSource.segments.forEach(function (segment) {
+                        // timestampBase for each segment, and calculate total duration
+                        segment.timestampBase = totalDuration;
+                        totalDuration += segment.duration;
+                        // params needed by IOController
+                        segment.cors = mediaDataSource.cors;
+                        segment.withCredentials = mediaDataSource.withCredentials;
+                        // referrer policy control, if exist
+                        if (config.referrerPolicy) {
+                            segment.referrerPolicy = config.referrerPolicy;
+                        }
+                    });
+
+                    if (!isNaN(totalDuration) && this._mediaDataSource.duration !== totalDuration) {
+                        this._mediaDataSource.duration = totalDuration;
+                    }
+
+                    this._mediaInfo = null;
+                    this._demuxer = null;
+                    this._remuxer = null;
+                    this._ioctl = null;
+
+                    this._pendingSeekTime = null;
+                    this._pendingResolveSeekPoint = null;
+
+                    this._statisticsReporter = null;
+                }
+
+                _createClass(TransmuxingController, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        this._mediaInfo = null;
+                        this._mediaDataSource = null;
+
+                        if (this._statisticsReporter) {
+                            this._disableStatisticsReporter();
+                        }
+                        if (this._ioctl) {
+                            this._ioctl.destroy();
+                            this._ioctl = null;
+                        }
+                        if (this._demuxer) {
+                            this._demuxer.destroy();
+                            this._demuxer = null;
+                        }
+                        if (this._remuxer) {
+                            this._remuxer.destroy();
+                            this._remuxer = null;
+                        }
+
+                        this._emitter.removeAllListeners();
+                        this._emitter = null;
+                    }
+                }, {
+                    key: 'on',
+                    value: function on(event, listener) {
+                        this._emitter.addListener(event, listener);
+                    }
+                }, {
+                    key: 'off',
+                    value: function off(event, listener) {
+                        this._emitter.removeListener(event, listener);
+                    }
+                }, {
+                    key: 'start',
+                    value: function start() {
+                        this._loadSegment(0);
+                        this._enableStatisticsReporter();
+                    }
+                }, {
+                    key: '_loadSegment',
+                    value: function _loadSegment(segmentIndex, optionalFrom) {
+                        this._currentSegmentIndex = segmentIndex;
+                        var dataSource = this._mediaDataSource.segments[segmentIndex];
+
+                        var ioctl = this._ioctl = new _ioController2.default(dataSource, this._config, segmentIndex);
+                        ioctl.onError = this._onIOException.bind(this);
+                        ioctl.onSeeked = this._onIOSeeked.bind(this);
+                        ioctl.onComplete = this._onIOComplete.bind(this);
+                        ioctl.onRedirect = this._onIORedirect.bind(this);
+                        ioctl.onRecoveredEarlyEof = this._onIORecoveredEarlyEof.bind(this);
+
+                        if (optionalFrom) {
+                            this._demuxer.bindDataSource(this._ioctl);
+                        } else {
+                            ioctl.onDataArrival = this._onInitChunkArrival.bind(this);
+                        }
+
+                        ioctl.open(optionalFrom);
+                    }
+                }, {
+                    key: 'stop',
+                    value: function stop() {
+                        this._internalAbort();
+                        this._disableStatisticsReporter();
+                    }
+                }, {
+                    key: '_internalAbort',
+                    value: function _internalAbort() {
+                        if (this._ioctl) {
+                            this._ioctl.destroy();
+                            this._ioctl = null;
+                        }
+                    }
+                }, {
+                    key: 'pause',
+                    value: function pause() {
+                        // take a rest
+                        if (this._ioctl && this._ioctl.isWorking()) {
+                            this._ioctl.pause();
+                            this._disableStatisticsReporter();
+                        }
+                    }
+                }, {
+                    key: 'resume',
+                    value: function resume() {
+                        if (this._ioctl && this._ioctl.isPaused()) {
+                            this._ioctl.resume();
+                            this._enableStatisticsReporter();
+                        }
+                    }
+                }, {
+                    key: 'seek',
+                    value: function seek(milliseconds) {
+                        if (this._mediaInfo == null || !this._mediaInfo.isSeekable()) {
+                            return;
+                        }
+
+                        var targetSegmentIndex = this._searchSegmentIndexContains(milliseconds);
+
+                        if (targetSegmentIndex === this._currentSegmentIndex) {
+                            // intra-segment seeking
+                            var segmentInfo = this._mediaInfo.segments[targetSegmentIndex];
+
+                            if (segmentInfo == undefined) {
+                                // current segment loading started, but mediainfo hasn't received yet
+                                // wait for the metadata loaded, then seek to expected position
+                                this._pendingSeekTime = milliseconds;
+                            } else {
+                                var keyframe = segmentInfo.getNearestKeyframe(milliseconds);
+                                this._remuxer.seek(keyframe.milliseconds);
+                                this._ioctl.seek(keyframe.fileposition);
+                                // Will be resolved in _onRemuxerMediaSegmentArrival()
+                                this._pendingResolveSeekPoint = keyframe.milliseconds;
+                            }
+                        } else {
+                            // cross-segment seeking
+                            var targetSegmentInfo = this._mediaInfo.segments[targetSegmentIndex];
+
+                            if (targetSegmentInfo == undefined) {
+                                // target segment hasn't been loaded. We need metadata then seek to expected time
+                                this._pendingSeekTime = milliseconds;
+                                this._internalAbort();
+                                this._remuxer.seek();
+                                this._remuxer.insertDiscontinuity();
+                                this._loadSegment(targetSegmentIndex);
+                                // Here we wait for the metadata loaded, then seek to expected position
+                            } else {
+                                // We have target segment's metadata, direct seek to target position
+                                var _keyframe = targetSegmentInfo.getNearestKeyframe(milliseconds);
+                                this._internalAbort();
+                                this._remuxer.seek(milliseconds);
+                                this._remuxer.insertDiscontinuity();
+                                this._demuxer.resetMediaInfo();
+                                this._demuxer.timestampBase = this._mediaDataSource.segments[targetSegmentIndex].timestampBase;
+                                this._loadSegment(targetSegmentIndex, _keyframe.fileposition);
+                                this._pendingResolveSeekPoint = _keyframe.milliseconds;
+                                this._reportSegmentMediaInfo(targetSegmentIndex);
+                            }
+                        }
+
+                        this._enableStatisticsReporter();
+                    }
+                }, {
+                    key: '_searchSegmentIndexContains',
+                    value: function _searchSegmentIndexContains(milliseconds) {
+                        var segments = this._mediaDataSource.segments;
+                        var idx = segments.length - 1;
+
+                        for (var i = 0; i < segments.length; i++) {
+                            if (milliseconds < segments[i].timestampBase) {
+                                idx = i - 1;
+                                break;
+                            }
+                        }
+                        return idx;
+                    }
+                }, {
+                    key: '_onInitChunkArrival',
+                    value: function _onInitChunkArrival(data, byteStart) {
+                        var _this = this;
+
+                        var probeData = null;
+                        var consumed = 0;
+
+                        if (byteStart > 0) {
+                            // IOController seeked immediately after opened, byteStart > 0 callback may received
+                            this._demuxer.bindDataSource(this._ioctl);
+                            this._demuxer.timestampBase = this._mediaDataSource.segments[this._currentSegmentIndex].timestampBase;
+
+                            consumed = this._demuxer.parseChunks(data, byteStart);
+                        } else if ((probeData = _flvDemuxer2.default.probe(data)).match) {
+                            // Always create new FLVDemuxer
+                            this._demuxer = new _flvDemuxer2.default(probeData, this._config);
+
+                            if (!this._remuxer) {
+                                this._remuxer = new _mp4Remuxer2.default(this._config);
+                            }
+
+                            var mds = this._mediaDataSource;
+                            if (mds.duration != undefined && !isNaN(mds.duration)) {
+                                this._demuxer.overridedDuration = mds.duration;
+                            }
+                            if (typeof mds.hasAudio === 'boolean') {
+                                this._demuxer.overridedHasAudio = mds.hasAudio;
+                            }
+                            if (typeof mds.hasVideo === 'boolean') {
+                                this._demuxer.overridedHasVideo = mds.hasVideo;
+                            }
+
+                            this._demuxer.timestampBase = mds.segments[this._currentSegmentIndex].timestampBase;
+
+                            this._demuxer.onError = this._onDemuxException.bind(this);
+                            this._demuxer.onMediaInfo = this._onMediaInfo.bind(this);
+                            this._demuxer.onMetaDataArrived = this._onMetaDataArrived.bind(this);
+                            this._demuxer.onScriptDataArrived = this._onScriptDataArrived.bind(this);
+
+                            this._remuxer.bindDataSource(this._demuxer.bindDataSource(this._ioctl));
+
+                            this._remuxer.onInitSegment = this._onRemuxerInitSegmentArrival.bind(this);
+                            this._remuxer.onMediaSegment = this._onRemuxerMediaSegmentArrival.bind(this);
+
+                            consumed = this._demuxer.parseChunks(data, byteStart);
+                        } else {
+                            probeData = null;
+                            _logger2.default.e(this.TAG, 'Non-FLV, Unsupported media type!');
+                            Promise.resolve().then(function () {
+                                _this._internalAbort();
+                            });
+                            this._emitter.emit(_transmuxingEvents2.default.DEMUX_ERROR, _demuxErrors2.default.FORMAT_UNSUPPORTED, 'Non-FLV, Unsupported media type');
+
+                            consumed = 0;
+                        }
+
+                        return consumed;
+                    }
+                }, {
+                    key: '_onMediaInfo',
+                    value: function _onMediaInfo(mediaInfo) {
+                        var _this2 = this;
+
+                        if (this._mediaInfo == null) {
+                            // Store first segment's mediainfo as global mediaInfo
+                            this._mediaInfo = Object.assign({}, mediaInfo);
+                            this._mediaInfo.keyframesIndex = null;
+                            this._mediaInfo.segments = [];
+                            this._mediaInfo.segmentCount = this._mediaDataSource.segments.length;
+                            Object.setPrototypeOf(this._mediaInfo, _mediaInfo2.default.prototype);
+                        }
+
+                        var segmentInfo = Object.assign({}, mediaInfo);
+                        Object.setPrototypeOf(segmentInfo, _mediaInfo2.default.prototype);
+                        this._mediaInfo.segments[this._currentSegmentIndex] = segmentInfo;
+
+                        // notify mediaInfo update
+                        this._reportSegmentMediaInfo(this._currentSegmentIndex);
+
+                        if (this._pendingSeekTime != null) {
+                            Promise.resolve().then(function () {
+                                var target = _this2._pendingSeekTime;
+                                _this2._pendingSeekTime = null;
+                                _this2.seek(target);
+                            });
+                        }
+                    }
+                }, {
+                    key: '_onMetaDataArrived',
+                    value: function _onMetaDataArrived(metadata) {
+                        this._emitter.emit(_transmuxingEvents2.default.METADATA_ARRIVED, metadata);
+                    }
+                }, {
+                    key: '_onScriptDataArrived',
+                    value: function _onScriptDataArrived(data) {
+                        this._emitter.emit(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, data);
+                    }
+                }, {
+                    key: '_onIOSeeked',
+                    value: function _onIOSeeked() {
+                        this._remuxer.insertDiscontinuity();
+                    }
+                }, {
+                    key: '_onIOComplete',
+                    value: function _onIOComplete(extraData) {
+                        var segmentIndex = extraData;
+                        var nextSegmentIndex = segmentIndex + 1;
+
+                        if (nextSegmentIndex < this._mediaDataSource.segments.length) {
+                            this._internalAbort();
+                            this._remuxer.flushStashedSamples();
+                            this._loadSegment(nextSegmentIndex);
+                        } else {
+                            this._remuxer.flushStashedSamples();
+                            this._emitter.emit(_transmuxingEvents2.default.LOADING_COMPLETE);
+                            this._disableStatisticsReporter();
+                        }
+                    }
+                }, {
+                    key: '_onIORedirect',
+                    value: function _onIORedirect(redirectedURL) {
+                        var segmentIndex = this._ioctl.extraData;
+                        this._mediaDataSource.segments[segmentIndex].redirectedURL = redirectedURL;
+                    }
+                }, {
+                    key: '_onIORecoveredEarlyEof',
+                    value: function _onIORecoveredEarlyEof() {
+                        this._emitter.emit(_transmuxingEvents2.default.RECOVERED_EARLY_EOF);
+                    }
+                }, {
+                    key: '_onIOException',
+                    value: function _onIOException(type, info) {
+                        _logger2.default.e(this.TAG, 'IOException: type = ' + type + ', code = ' + info.code + ', msg = ' + info.msg);
+                        this._emitter.emit(_transmuxingEvents2.default.IO_ERROR, type, info);
+                        this._disableStatisticsReporter();
+                    }
+                }, {
+                    key: '_onDemuxException',
+                    value: function _onDemuxException(type, info) {
+                        _logger2.default.e(this.TAG, 'DemuxException: type = ' + type + ', info = ' + info);
+                        this._emitter.emit(_transmuxingEvents2.default.DEMUX_ERROR, type, info);
+                    }
+                }, {
+                    key: '_onRemuxerInitSegmentArrival',
+                    value: function _onRemuxerInitSegmentArrival(type, initSegment) {
+                        this._emitter.emit(_transmuxingEvents2.default.INIT_SEGMENT, type, initSegment);
+                    }
+                }, {
+                    key: '_onRemuxerMediaSegmentArrival',
+                    value: function _onRemuxerMediaSegmentArrival(type, mediaSegment) {
+                        if (this._pendingSeekTime != null) {
+                            // Media segments after new-segment cross-seeking should be dropped.
+                            return;
+                        }
+                        this._emitter.emit(_transmuxingEvents2.default.MEDIA_SEGMENT, type, mediaSegment);
+
+                        // Resolve pending seekPoint
+                        if (this._pendingResolveSeekPoint != null && type === 'video') {
+                            var syncPoints = mediaSegment.info.syncPoints;
+                            var seekpoint = this._pendingResolveSeekPoint;
+                            this._pendingResolveSeekPoint = null;
+
+                            // Safari: Pass PTS for recommend_seekpoint
+                            if (_browser2.default.safari && syncPoints.length > 0 && syncPoints[0].originalDts === seekpoint) {
+                                seekpoint = syncPoints[0].pts;
+                            }
+                            // else: use original DTS (keyframe.milliseconds)
+
+                            this._emitter.emit(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, seekpoint);
+                        }
+                    }
+                }, {
+                    key: '_enableStatisticsReporter',
+                    value: function _enableStatisticsReporter() {
+                        if (this._statisticsReporter == null) {
+                            this._statisticsReporter = self.setInterval(this._reportStatisticsInfo.bind(this), this._config.statisticsInfoReportInterval);
+                        }
+                    }
+                }, {
+                    key: '_disableStatisticsReporter',
+                    value: function _disableStatisticsReporter() {
+                        if (this._statisticsReporter) {
+                            self.clearInterval(this._statisticsReporter);
+                            this._statisticsReporter = null;
+                        }
+                    }
+                }, {
+                    key: '_reportSegmentMediaInfo',
+                    value: function _reportSegmentMediaInfo(segmentIndex) {
+                        var segmentInfo = this._mediaInfo.segments[segmentIndex];
+                        var exportInfo = Object.assign({}, segmentInfo);
+
+                        exportInfo.duration = this._mediaInfo.duration;
+                        exportInfo.segmentCount = this._mediaInfo.segmentCount;
+                        delete exportInfo.segments;
+                        delete exportInfo.keyframesIndex;
+
+                        this._emitter.emit(_transmuxingEvents2.default.MEDIA_INFO, exportInfo);
+                    }
+                }, {
+                    key: '_reportStatisticsInfo',
+                    value: function _reportStatisticsInfo() {
+                        var info = {};
+
+                        info.url = this._ioctl.currentURL;
+                        info.hasRedirect = this._ioctl.hasRedirect;
+                        if (info.hasRedirect) {
+                            info.redirectedURL = this._ioctl.currentRedirectedURL;
+                        }
+
+                        info.speed = this._ioctl.currentSpeed;
+                        info.loaderType = this._ioctl.loaderType;
+                        info.currentSegmentIndex = this._currentSegmentIndex;
+                        info.totalSegmentCount = this._mediaDataSource.segments.length;
+
+                        this._emitter.emit(_transmuxingEvents2.default.STATISTICS_INFO, info);
+                    }
+                }]);
+
+                return TransmuxingController;
+            }();
+
+            exports.default = TransmuxingController;
+
+        }, { "../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) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var TransmuxingEvents = {
+                IO_ERROR: 'io_error',
+                DEMUX_ERROR: 'demux_error',
+                INIT_SEGMENT: 'init_segment',
+                MEDIA_SEGMENT: 'media_segment',
+                LOADING_COMPLETE: 'loading_complete',
+                RECOVERED_EARLY_EOF: 'recovered_early_eof',
+                MEDIA_INFO: 'media_info',
+                METADATA_ARRIVED: 'metadata_arrived',
+                SCRIPTDATA_ARRIVED: 'scriptdata_arrived',
+                STATISTICS_INFO: 'statistics_info',
+                RECOMMEND_SEEKPOINT: 'recommend_seekpoint'
+            };
+
+            exports.default = TransmuxingEvents;
+
+        }, {}], 14: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _loggingControl = _dereq_('../utils/logging-control.js');
+
+            var _loggingControl2 = _interopRequireDefault(_loggingControl);
+
+            var _polyfill = _dereq_('../utils/polyfill.js');
+
+            var _polyfill2 = _interopRequireDefault(_polyfill);
+
+            var _transmuxingController = _dereq_('./transmuxing-controller.js');
+
+            var _transmuxingController2 = _interopRequireDefault(_transmuxingController);
+
+            var _transmuxingEvents = _dereq_('./transmuxing-events.js');
+
+            var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            /* post message to worker:
+               data: {
+                   cmd: string
+                   param: any
+               }
+            
+               receive message from worker:
+               data: {
+                   msg: string,
+                   data: any
+               }
+             */
+
+            var TransmuxingWorker = function TransmuxingWorker(self) {
+
+                var TAG = 'TransmuxingWorker';
+                var controller = null;
+                var logcatListener = onLogcatCallback.bind(this);
+
+                _polyfill2.default.install();
+
+                self.addEventListener('message', function (e) {
+                    switch (e.data.cmd) {
+                        case 'init':
+                            controller = new _transmuxingController2.default(e.data.param[0], e.data.param[1]);
+                            controller.on(_transmuxingEvents2.default.IO_ERROR, onIOError.bind(this));
+                            controller.on(_transmuxingEvents2.default.DEMUX_ERROR, onDemuxError.bind(this));
+                            controller.on(_transmuxingEvents2.default.INIT_SEGMENT, onInitSegment.bind(this));
+                            controller.on(_transmuxingEvents2.default.MEDIA_SEGMENT, onMediaSegment.bind(this));
+                            controller.on(_transmuxingEvents2.default.LOADING_COMPLETE, onLoadingComplete.bind(this));
+                            controller.on(_transmuxingEvents2.default.RECOVERED_EARLY_EOF, onRecoveredEarlyEof.bind(this));
+                            controller.on(_transmuxingEvents2.default.MEDIA_INFO, onMediaInfo.bind(this));
+                            controller.on(_transmuxingEvents2.default.METADATA_ARRIVED, onMetaDataArrived.bind(this));
+                            controller.on(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, onScriptDataArrived.bind(this));
+                            controller.on(_transmuxingEvents2.default.STATISTICS_INFO, onStatisticsInfo.bind(this));
+                            controller.on(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, onRecommendSeekpoint.bind(this));
+                            break;
+                        case 'destroy':
+                            if (controller) {
+                                controller.destroy();
+                                controller = null;
+                            }
+                            self.postMessage({ msg: 'destroyed' });
+                            break;
+                        case 'start':
+                            controller.start();
+                            break;
+                        case 'stop':
+                            controller.stop();
+                            break;
+                        case 'seek':
+                            controller.seek(e.data.param);
+                            break;
+                        case 'pause':
+                            controller.pause();
+                            break;
+                        case 'resume':
+                            controller.resume();
+                            break;
+                        case 'logging_config':
+                            {
+                                var config = e.data.param;
+                                _loggingControl2.default.applyConfig(config);
+
+                                if (config.enableCallback === true) {
+                                    _loggingControl2.default.addLogListener(logcatListener);
+                                } else {
+                                    _loggingControl2.default.removeLogListener(logcatListener);
+                                }
+                                break;
+                            }
+                    }
+                });
+
+                function onInitSegment(type, initSegment) {
+                    var obj = {
+                        msg: _transmuxingEvents2.default.INIT_SEGMENT,
+                        data: {
+                            type: type,
+                            data: initSegment
+                        }
+                    };
+                    self.postMessage(obj, [initSegment.data]); // data: ArrayBuffer
+                }
+
+                function onMediaSegment(type, mediaSegment) {
+                    var obj = {
+                        msg: _transmuxingEvents2.default.MEDIA_SEGMENT,
+                        data: {
+                            type: type,
+                            data: mediaSegment
+                        }
+                    };
+                    self.postMessage(obj, [mediaSegment.data]); // data: ArrayBuffer
+                }
+
+                function onLoadingComplete() {
+                    var obj = {
+                        msg: _transmuxingEvents2.default.LOADING_COMPLETE
+                    };
+                    self.postMessage(obj);
+                }
+
+                function onRecoveredEarlyEof() {
+                    var obj = {
+                        msg: _transmuxingEvents2.default.RECOVERED_EARLY_EOF
+                    };
+                    self.postMessage(obj);
+                }
+
+                function onMediaInfo(mediaInfo) {
+                    var obj = {
+                        msg: _transmuxingEvents2.default.MEDIA_INFO,
+                        data: mediaInfo
+                    };
+                    self.postMessage(obj);
+                }
+
+                function onMetaDataArrived(metadata) {
+                    var obj = {
+                        msg: _transmuxingEvents2.default.METADATA_ARRIVED,
+                        data: metadata
+                    };
+                    self.postMessage(obj);
+                }
+
+                function onScriptDataArrived(data) {
+                    var obj = {
+                        msg: _transmuxingEvents2.default.SCRIPTDATA_ARRIVED,
+                        data: data
+                    };
+                    self.postMessage(obj);
+                }
+
+                function onStatisticsInfo(statInfo) {
+                    var obj = {
+                        msg: _transmuxingEvents2.default.STATISTICS_INFO,
+                        data: statInfo
+                    };
+                    self.postMessage(obj);
+                }
+
+                function onIOError(type, info) {
+                    self.postMessage({
+                        msg: _transmuxingEvents2.default.IO_ERROR,
+                        data: {
+                            type: type,
+                            info: info
+                        }
+                    });
+                }
+
+                function onDemuxError(type, info) {
+                    self.postMessage({
+                        msg: _transmuxingEvents2.default.DEMUX_ERROR,
+                        data: {
+                            type: type,
+                            info: info
+                        }
+                    });
+                }
+
+                function onRecommendSeekpoint(milliseconds) {
+                    self.postMessage({
+                        msg: _transmuxingEvents2.default.RECOMMEND_SEEKPOINT,
+                        data: milliseconds
+                    });
+                }
+
+                function onLogcatCallback(type, str) {
+                    self.postMessage({
+                        msg: 'logcat_callback',
+                        data: {
+                            type: type,
+                            logcat: str
+                        }
+                    });
+                }
+            }; /*
     * Copyright (C) 2016 Bilibili. All Rights Reserved.
     *
     * @author zheng qian <xqq@xqq.im>
@@ -4059,16 +4070,16 @@
     * limitations under the License.
     */
 
-exports.default = TransmuxingWorker;
+            exports.default = TransmuxingWorker;
 
-},{"../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){
-'use strict';
+        }, { "../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) {
+            'use strict';
 
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
 
-var _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; }; }(); /*
+            var _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; }; }(); /*
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * Copyright (C) 2016 Bilibili. All Rights Reserved.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       *
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * @author zheng qian <xqq@xqq.im>
@@ -4086,1642 +4097,1642 @@
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * limitations under the License.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       */
 
-var _logger = _dereq_('../utils/logger.js');
+            var _logger = _dereq_('../utils/logger.js');
 
-var _logger2 = _interopRequireDefault(_logger);
+            var _logger2 = _interopRequireDefault(_logger);
 
-var _utf8Conv = _dereq_('../utils/utf8-conv.js');
+            var _utf8Conv = _dereq_('../utils/utf8-conv.js');
 
-var _utf8Conv2 = _interopRequireDefault(_utf8Conv);
+            var _utf8Conv2 = _interopRequireDefault(_utf8Conv);
 
-var _exception = _dereq_('../utils/exception.js');
+            var _exception = _dereq_('../utils/exception.js');
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var le = function () {
-    var buf = new ArrayBuffer(2);
-    new DataView(buf).setInt16(0, 256, true); // little-endian write
-    return new Int16Array(buf)[0] === 256; // platform-spec read, if equal then LE
-}();
+            var le = function () {
+                var buf = new ArrayBuffer(2);
+                new DataView(buf).setInt16(0, 256, true); // little-endian write
+                return new Int16Array(buf)[0] === 256; // platform-spec read, if equal then LE
+            }();
 
-var AMF = function () {
-    function AMF() {
-        _classCallCheck(this, AMF);
-    }
+            var AMF = function () {
+                function AMF() {
+                    _classCallCheck(this, AMF);
+                }
 
-    _createClass(AMF, null, [{
-        key: 'parseScriptData',
-        value: function parseScriptData(arrayBuffer, dataOffset, dataSize) {
-            var data = {};
+                _createClass(AMF, null, [{
+                    key: 'parseScriptData',
+                    value: function parseScriptData(arrayBuffer, dataOffset, dataSize) {
+                        var data = {};
 
-            try {
-                var name = AMF.parseValue(arrayBuffer, dataOffset, dataSize);
-                var value = AMF.parseValue(arrayBuffer, dataOffset + name.size, dataSize - name.size);
+                        try {
+                            var name = AMF.parseValue(arrayBuffer, dataOffset, dataSize);
+                            var value = AMF.parseValue(arrayBuffer, dataOffset + name.size, dataSize - name.size);
 
-                data[name.data] = value.data;
-            } catch (e) {
-                _logger2.default.e('AMF', e.toString());
-            }
-
-            return data;
-        }
-    }, {
-        key: 'parseObject',
-        value: function parseObject(arrayBuffer, dataOffset, dataSize) {
-            if (dataSize < 3) {
-                throw new _exception.IllegalStateException('Data not enough when parse ScriptDataObject');
-            }
-            var name = AMF.parseString(arrayBuffer, dataOffset, dataSize);
-            var value = AMF.parseValue(arrayBuffer, dataOffset + name.size, dataSize - name.size);
-            var isObjectEnd = value.objectEnd;
-
-            return {
-                data: {
-                    name: name.data,
-                    value: value.data
-                },
-                size: name.size + value.size,
-                objectEnd: isObjectEnd
-            };
-        }
-    }, {
-        key: 'parseVariable',
-        value: function parseVariable(arrayBuffer, dataOffset, dataSize) {
-            return AMF.parseObject(arrayBuffer, dataOffset, dataSize);
-        }
-    }, {
-        key: 'parseString',
-        value: function parseString(arrayBuffer, dataOffset, dataSize) {
-            if (dataSize < 2) {
-                throw new _exception.IllegalStateException('Data not enough when parse String');
-            }
-            var v = new DataView(arrayBuffer, dataOffset, dataSize);
-            var length = v.getUint16(0, !le);
-
-            var str = void 0;
-            if (length > 0) {
-                str = (0, _utf8Conv2.default)(new Uint8Array(arrayBuffer, dataOffset + 2, length));
-            } else {
-                str = '';
-            }
-
-            return {
-                data: str,
-                size: 2 + length
-            };
-        }
-    }, {
-        key: 'parseLongString',
-        value: function parseLongString(arrayBuffer, dataOffset, dataSize) {
-            if (dataSize < 4) {
-                throw new _exception.IllegalStateException('Data not enough when parse LongString');
-            }
-            var v = new DataView(arrayBuffer, dataOffset, dataSize);
-            var length = v.getUint32(0, !le);
-
-            var str = void 0;
-            if (length > 0) {
-                str = (0, _utf8Conv2.default)(new Uint8Array(arrayBuffer, dataOffset + 4, length));
-            } else {
-                str = '';
-            }
-
-            return {
-                data: str,
-                size: 4 + length
-            };
-        }
-    }, {
-        key: 'parseDate',
-        value: function parseDate(arrayBuffer, dataOffset, dataSize) {
-            if (dataSize < 10) {
-                throw new _exception.IllegalStateException('Data size invalid when parse Date');
-            }
-            var v = new DataView(arrayBuffer, dataOffset, dataSize);
-            var timestamp = v.getFloat64(0, !le);
-            var localTimeOffset = v.getInt16(8, !le);
-            timestamp += localTimeOffset * 60 * 1000; // get UTC time
-
-            return {
-                data: new Date(timestamp),
-                size: 8 + 2
-            };
-        }
-    }, {
-        key: 'parseValue',
-        value: function parseValue(arrayBuffer, dataOffset, dataSize) {
-            if (dataSize < 1) {
-                throw new _exception.IllegalStateException('Data not enough when parse Value');
-            }
-
-            var v = new DataView(arrayBuffer, dataOffset, dataSize);
-
-            var offset = 1;
-            var type = v.getUint8(0);
-            var value = void 0;
-            var objectEnd = false;
-
-            try {
-                switch (type) {
-                    case 0:
-                        // Number(Double) type
-                        value = v.getFloat64(1, !le);
-                        offset += 8;
-                        break;
-                    case 1:
-                        {
-                            // Boolean type
-                            var b = v.getUint8(1);
-                            value = b ? true : false;
-                            offset += 1;
-                            break;
+                            data[name.data] = value.data;
+                        } catch (e) {
+                            _logger2.default.e('AMF', e.toString());
                         }
-                    case 2:
-                        {
-                            // String type
-                            var amfstr = AMF.parseString(arrayBuffer, dataOffset + 1, dataSize - 1);
-                            value = amfstr.data;
-                            offset += amfstr.size;
-                            break;
+
+                        return data;
+                    }
+                }, {
+                    key: 'parseObject',
+                    value: function parseObject(arrayBuffer, dataOffset, dataSize) {
+                        if (dataSize < 3) {
+                            throw new _exception.IllegalStateException('Data not enough when parse ScriptDataObject');
                         }
-                    case 3:
-                        {
-                            // Object(s) type
-                            value = {};
-                            var terminal = 0; // workaround for malformed Objects which has missing ScriptDataObjectEnd
-                            if ((v.getUint32(dataSize - 4, !le) & 0x00FFFFFF) === 9) {
-                                terminal = 3;
-                            }
-                            while (offset < dataSize - 4) {
-                                // 4 === type(UI8) + ScriptDataObjectEnd(UI24)
-                                var amfobj = AMF.parseObject(arrayBuffer, dataOffset + offset, dataSize - offset - terminal);
-                                if (amfobj.objectEnd) break;
-                                value[amfobj.data.name] = amfobj.data.value;
-                                offset += amfobj.size;
-                            }
-                            if (offset <= dataSize - 3) {
-                                var marker = v.getUint32(offset - 1, !le) & 0x00FFFFFF;
-                                if (marker === 9) {
-                                    offset += 3;
-                                }
-                            }
-                            break;
+                        var name = AMF.parseString(arrayBuffer, dataOffset, dataSize);
+                        var value = AMF.parseValue(arrayBuffer, dataOffset + name.size, dataSize - name.size);
+                        var isObjectEnd = value.objectEnd;
+
+                        return {
+                            data: {
+                                name: name.data,
+                                value: value.data
+                            },
+                            size: name.size + value.size,
+                            objectEnd: isObjectEnd
+                        };
+                    }
+                }, {
+                    key: 'parseVariable',
+                    value: function parseVariable(arrayBuffer, dataOffset, dataSize) {
+                        return AMF.parseObject(arrayBuffer, dataOffset, dataSize);
+                    }
+                }, {
+                    key: 'parseString',
+                    value: function parseString(arrayBuffer, dataOffset, dataSize) {
+                        if (dataSize < 2) {
+                            throw new _exception.IllegalStateException('Data not enough when parse String');
                         }
-                    case 8:
-                        {
-                            // ECMA array type (Mixed array)
-                            value = {};
-                            offset += 4; // ECMAArrayLength(UI32)
-                            var _terminal = 0; // workaround for malformed MixedArrays which has missing ScriptDataObjectEnd
-                            if ((v.getUint32(dataSize - 4, !le) & 0x00FFFFFF) === 9) {
-                                _terminal = 3;
-                            }
-                            while (offset < dataSize - 8) {
-                                // 8 === type(UI8) + ECMAArrayLength(UI32) + ScriptDataVariableEnd(UI24)
-                                var amfvar = AMF.parseVariable(arrayBuffer, dataOffset + offset, dataSize - offset - _terminal);
-                                if (amfvar.objectEnd) break;
-                                value[amfvar.data.name] = amfvar.data.value;
-                                offset += amfvar.size;
-                            }
-                            if (offset <= dataSize - 3) {
-                                var _marker = v.getUint32(offset - 1, !le) & 0x00FFFFFF;
-                                if (_marker === 9) {
-                                    offset += 3;
-                                }
-                            }
-                            break;
+                        var v = new DataView(arrayBuffer, dataOffset, dataSize);
+                        var length = v.getUint16(0, !le);
+
+                        var str = void 0;
+                        if (length > 0) {
+                            str = (0, _utf8Conv2.default)(new Uint8Array(arrayBuffer, dataOffset + 2, length));
+                        } else {
+                            str = '';
                         }
-                    case 9:
-                        // ScriptDataObjectEnd
-                        value = undefined;
-                        offset = 1;
-                        objectEnd = true;
-                        break;
-                    case 10:
-                        {
-                            // Strict array type
-                            // ScriptDataValue[n]. NOTE: according to video_file_format_spec_v10_1.pdf
-                            value = [];
-                            var strictArrayLength = v.getUint32(1, !le);
+
+                        return {
+                            data: str,
+                            size: 2 + length
+                        };
+                    }
+                }, {
+                    key: 'parseLongString',
+                    value: function parseLongString(arrayBuffer, dataOffset, dataSize) {
+                        if (dataSize < 4) {
+                            throw new _exception.IllegalStateException('Data not enough when parse LongString');
+                        }
+                        var v = new DataView(arrayBuffer, dataOffset, dataSize);
+                        var length = v.getUint32(0, !le);
+
+                        var str = void 0;
+                        if (length > 0) {
+                            str = (0, _utf8Conv2.default)(new Uint8Array(arrayBuffer, dataOffset + 4, length));
+                        } else {
+                            str = '';
+                        }
+
+                        return {
+                            data: str,
+                            size: 4 + length
+                        };
+                    }
+                }, {
+                    key: 'parseDate',
+                    value: function parseDate(arrayBuffer, dataOffset, dataSize) {
+                        if (dataSize < 10) {
+                            throw new _exception.IllegalStateException('Data size invalid when parse Date');
+                        }
+                        var v = new DataView(arrayBuffer, dataOffset, dataSize);
+                        var timestamp = v.getFloat64(0, !le);
+                        var localTimeOffset = v.getInt16(8, !le);
+                        timestamp += localTimeOffset * 60 * 1000; // get UTC time
+
+                        return {
+                            data: new Date(timestamp),
+                            size: 8 + 2
+                        };
+                    }
+                }, {
+                    key: 'parseValue',
+                    value: function parseValue(arrayBuffer, dataOffset, dataSize) {
+                        if (dataSize < 1) {
+                            throw new _exception.IllegalStateException('Data not enough when parse Value');
+                        }
+
+                        var v = new DataView(arrayBuffer, dataOffset, dataSize);
+
+                        var offset = 1;
+                        var type = v.getUint8(0);
+                        var value = void 0;
+                        var objectEnd = false;
+
+                        try {
+                            switch (type) {
+                                case 0:
+                                    // Number(Double) type
+                                    value = v.getFloat64(1, !le);
+                                    offset += 8;
+                                    break;
+                                case 1:
+                                    {
+                                        // Boolean type
+                                        var b = v.getUint8(1);
+                                        value = b ? true : false;
+                                        offset += 1;
+                                        break;
+                                    }
+                                case 2:
+                                    {
+                                        // String type
+                                        var amfstr = AMF.parseString(arrayBuffer, dataOffset + 1, dataSize - 1);
+                                        value = amfstr.data;
+                                        offset += amfstr.size;
+                                        break;
+                                    }
+                                case 3:
+                                    {
+                                        // Object(s) type
+                                        value = {};
+                                        var terminal = 0; // workaround for malformed Objects which has missing ScriptDataObjectEnd
+                                        if ((v.getUint32(dataSize - 4, !le) & 0x00FFFFFF) === 9) {
+                                            terminal = 3;
+                                        }
+                                        while (offset < dataSize - 4) {
+                                            // 4 === type(UI8) + ScriptDataObjectEnd(UI24)
+                                            var amfobj = AMF.parseObject(arrayBuffer, dataOffset + offset, dataSize - offset - terminal);
+                                            if (amfobj.objectEnd) break;
+                                            value[amfobj.data.name] = amfobj.data.value;
+                                            offset += amfobj.size;
+                                        }
+                                        if (offset <= dataSize - 3) {
+                                            var marker = v.getUint32(offset - 1, !le) & 0x00FFFFFF;
+                                            if (marker === 9) {
+                                                offset += 3;
+                                            }
+                                        }
+                                        break;
+                                    }
+                                case 8:
+                                    {
+                                        // ECMA array type (Mixed array)
+                                        value = {};
+                                        offset += 4; // ECMAArrayLength(UI32)
+                                        var _terminal = 0; // workaround for malformed MixedArrays which has missing ScriptDataObjectEnd
+                                        if ((v.getUint32(dataSize - 4, !le) & 0x00FFFFFF) === 9) {
+                                            _terminal = 3;
+                                        }
+                                        while (offset < dataSize - 8) {
+                                            // 8 === type(UI8) + ECMAArrayLength(UI32) + ScriptDataVariableEnd(UI24)
+                                            var amfvar = AMF.parseVariable(arrayBuffer, dataOffset + offset, dataSize - offset - _terminal);
+                                            if (amfvar.objectEnd) break;
+                                            value[amfvar.data.name] = amfvar.data.value;
+                                            offset += amfvar.size;
+                                        }
+                                        if (offset <= dataSize - 3) {
+                                            var _marker = v.getUint32(offset - 1, !le) & 0x00FFFFFF;
+                                            if (_marker === 9) {
+                                                offset += 3;
+                                            }
+                                        }
+                                        break;
+                                    }
+                                case 9:
+                                    // ScriptDataObjectEnd
+                                    value = undefined;
+                                    offset = 1;
+                                    objectEnd = true;
+                                    break;
+                                case 10:
+                                    {
+                                        // Strict array type
+                                        // ScriptDataValue[n]. NOTE: according to video_file_format_spec_v10_1.pdf
+                                        value = [];
+                                        var strictArrayLength = v.getUint32(1, !le);
+                                        offset += 4;
+                                        for (var i = 0; i < strictArrayLength; i++) {
+                                            var val = AMF.parseValue(arrayBuffer, dataOffset + offset, dataSize - offset);
+                                            value.push(val.data);
+                                            offset += val.size;
+                                        }
+                                        break;
+                                    }
+                                case 11:
+                                    {
+                                        // Date type
+                                        var date = AMF.parseDate(arrayBuffer, dataOffset + 1, dataSize - 1);
+                                        value = date.data;
+                                        offset += date.size;
+                                        break;
+                                    }
+                                case 12:
+                                    {
+                                        // Long string type
+                                        var amfLongStr = AMF.parseString(arrayBuffer, dataOffset + 1, dataSize - 1);
+                                        value = amfLongStr.data;
+                                        offset += amfLongStr.size;
+                                        break;
+                                    }
+                                default:
+                                    // ignore and skip
+                                    offset = dataSize;
+                                    _logger2.default.w('AMF', 'Unsupported AMF value type ' + type);
+                            }
+                        } catch (e) {
+                            _logger2.default.e('AMF', e.toString());
+                        }
+
+                        return {
+                            data: value,
+                            size: offset,
+                            objectEnd: objectEnd
+                        };
+                    }
+                }]);
+
+                return AMF;
+            }();
+
+            exports.default = AMF;
+
+        }, { "../utils/exception.js": 40, "../utils/logger.js": 41, "../utils/utf8-conv.js": 44 }], 16: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var DemuxErrors = {
+                OK: 'OK',
+                FORMAT_ERROR: 'FormatError',
+                FORMAT_UNSUPPORTED: 'FormatUnsupported',
+                CODEC_UNSUPPORTED: 'CodecUnsupported'
+            };
+
+            exports.default = DemuxErrors;
+
+        }, {}], 17: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }(); /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
+
+            var _exception = _dereq_('../utils/exception.js');
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            // Exponential-Golomb buffer decoder
+            var ExpGolomb = function () {
+                function ExpGolomb(uint8array) {
+                    _classCallCheck(this, ExpGolomb);
+
+                    this.TAG = 'ExpGolomb';
+
+                    this._buffer = uint8array;
+                    this._buffer_index = 0;
+                    this._total_bytes = uint8array.byteLength;
+                    this._total_bits = uint8array.byteLength * 8;
+                    this._current_word = 0;
+                    this._current_word_bits_left = 0;
+                }
+
+                _createClass(ExpGolomb, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        this._buffer = null;
+                    }
+                }, {
+                    key: '_fillCurrentWord',
+                    value: function _fillCurrentWord() {
+                        var buffer_bytes_left = this._total_bytes - this._buffer_index;
+                        if (buffer_bytes_left <= 0) throw new _exception.IllegalStateException('ExpGolomb: _fillCurrentWord() but no bytes available');
+
+                        var bytes_read = Math.min(4, buffer_bytes_left);
+                        var word = new Uint8Array(4);
+                        word.set(this._buffer.subarray(this._buffer_index, this._buffer_index + bytes_read));
+                        this._current_word = new DataView(word.buffer).getUint32(0, false);
+
+                        this._buffer_index += bytes_read;
+                        this._current_word_bits_left = bytes_read * 8;
+                    }
+                }, {
+                    key: 'readBits',
+                    value: function readBits(bits) {
+                        if (bits > 32) throw new _exception.InvalidArgumentException('ExpGolomb: readBits() bits exceeded max 32bits!');
+
+                        if (bits <= this._current_word_bits_left) {
+                            var _result = this._current_word >>> 32 - bits;
+                            this._current_word <<= bits;
+                            this._current_word_bits_left -= bits;
+                            return _result;
+                        }
+
+                        var result = this._current_word_bits_left ? this._current_word : 0;
+                        result = result >>> 32 - this._current_word_bits_left;
+                        var bits_need_left = bits - this._current_word_bits_left;
+
+                        this._fillCurrentWord();
+                        var bits_read_next = Math.min(bits_need_left, this._current_word_bits_left);
+
+                        var result2 = this._current_word >>> 32 - bits_read_next;
+                        this._current_word <<= bits_read_next;
+                        this._current_word_bits_left -= bits_read_next;
+
+                        result = result << bits_read_next | result2;
+                        return result;
+                    }
+                }, {
+                    key: 'readBool',
+                    value: function readBool() {
+                        return this.readBits(1) === 1;
+                    }
+                }, {
+                    key: 'readByte',
+                    value: function readByte() {
+                        return this.readBits(8);
+                    }
+                }, {
+                    key: '_skipLeadingZero',
+                    value: function _skipLeadingZero() {
+                        var zero_count = void 0;
+                        for (zero_count = 0; zero_count < this._current_word_bits_left; zero_count++) {
+                            if (0 !== (this._current_word & 0x80000000 >>> zero_count)) {
+                                this._current_word <<= zero_count;
+                                this._current_word_bits_left -= zero_count;
+                                return zero_count;
+                            }
+                        }
+                        this._fillCurrentWord();
+                        return zero_count + this._skipLeadingZero();
+                    }
+                }, {
+                    key: 'readUEG',
+                    value: function readUEG() {
+                        // unsigned exponential golomb
+                        var leading_zeros = this._skipLeadingZero();
+                        return this.readBits(leading_zeros + 1) - 1;
+                    }
+                }, {
+                    key: 'readSEG',
+                    value: function readSEG() {
+                        // signed exponential golomb
+                        var value = this.readUEG();
+                        if (value & 0x01) {
+                            return value + 1 >>> 1;
+                        } else {
+                            return -1 * (value >>> 1);
+                        }
+                    }
+                }]);
+
+                return ExpGolomb;
+            }();
+
+            exports.default = ExpGolomb;
+
+        }, { "../utils/exception.js": 40 }], 18: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; };
+
+            var _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; }; }(); /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _amfParser = _dereq_('./amf-parser.js');
+
+            var _amfParser2 = _interopRequireDefault(_amfParser);
+
+            var _spsParser = _dereq_('./sps-parser.js');
+
+            var _spsParser2 = _interopRequireDefault(_spsParser);
+
+            var _demuxErrors = _dereq_('./demux-errors.js');
+
+            var _demuxErrors2 = _interopRequireDefault(_demuxErrors);
+
+            var _mediaInfo = _dereq_('../core/media-info.js');
+
+            var _mediaInfo2 = _interopRequireDefault(_mediaInfo);
+
+            var _exception = _dereq_('../utils/exception.js');
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            function Swap16(src) {
+                return src >>> 8 & 0xFF | (src & 0xFF) << 8;
+            }
+
+            function Swap32(src) {
+                return (src & 0xFF000000) >>> 24 | (src & 0x00FF0000) >>> 8 | (src & 0x0000FF00) << 8 | (src & 0x000000FF) << 24;
+            }
+
+            function ReadBig32(array, index) {
+                return array[index] << 24 | array[index + 1] << 16 | array[index + 2] << 8 | array[index + 3];
+            }
+
+            var FLVDemuxer = function () {
+                function FLVDemuxer(probeData, config) {
+                    _classCallCheck(this, FLVDemuxer);
+
+                    this.TAG = 'FLVDemuxer';
+
+                    this._config = config;
+
+                    this._onError = null;
+                    this._onMediaInfo = null;
+                    this._onMetaDataArrived = null;
+                    this._onScriptDataArrived = null;
+                    this._onTrackMetadata = null;
+                    this._onDataAvailable = null;
+
+                    this._dataOffset = probeData.dataOffset;
+                    this._firstParse = true;
+                    this._dispatch = false;
+
+                    this._hasAudio = probeData.hasAudioTrack;
+                    this._hasVideo = probeData.hasVideoTrack;
+
+                    this._hasAudioFlagOverrided = false;
+                    this._hasVideoFlagOverrided = false;
+
+                    this._audioInitialMetadataDispatched = false;
+                    this._videoInitialMetadataDispatched = false;
+
+                    this._mediaInfo = new _mediaInfo2.default();
+                    this._mediaInfo.hasAudio = this._hasAudio;
+                    this._mediaInfo.hasVideo = this._hasVideo;
+                    this._metadata = null;
+                    this._audioMetadata = null;
+                    this._videoMetadata = null;
+
+                    this._naluLengthSize = 4;
+                    this._timestampBase = 0; // int32, in milliseconds
+                    this._timescale = 1000;
+                    this._duration = 0; // int32, in milliseconds
+                    this._durationOverrided = false;
+                    this._referenceFrameRate = {
+                        fixed: true,
+                        fps: 23.976,
+                        fps_num: 23976,
+                        fps_den: 1000
+                    };
+
+                    this._flvSoundRateTable = [5500, 11025, 22050, 44100, 48000];
+
+                    this._mpegSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
+
+                    this._mpegAudioV10SampleRateTable = [44100, 48000, 32000, 0];
+                    this._mpegAudioV20SampleRateTable = [22050, 24000, 16000, 0];
+                    this._mpegAudioV25SampleRateTable = [11025, 12000, 8000, 0];
+
+                    this._mpegAudioL1BitRateTable = [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1];
+                    this._mpegAudioL2BitRateTable = [0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1];
+                    this._mpegAudioL3BitRateTable = [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1];
+
+                    this._videoTrack = { type: 'video', id: 1, sequenceNumber: 0, samples: [], length: 0 };
+                    this._audioTrack = { type: 'audio', id: 2, sequenceNumber: 0, samples: [], length: 0 };
+
+                    this._littleEndian = function () {
+                        var buf = new ArrayBuffer(2);
+                        new DataView(buf).setInt16(0, 256, true); // little-endian write
+                        return new Int16Array(buf)[0] === 256; // platform-spec read, if equal then LE
+                    }();
+                }
+
+                _createClass(FLVDemuxer, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        this._mediaInfo = null;
+                        this._metadata = null;
+                        this._audioMetadata = null;
+                        this._videoMetadata = null;
+                        this._videoTrack = null;
+                        this._audioTrack = null;
+
+                        this._onError = null;
+                        this._onMediaInfo = null;
+                        this._onMetaDataArrived = null;
+                        this._onScriptDataArrived = null;
+                        this._onTrackMetadata = null;
+                        this._onDataAvailable = null;
+                    }
+                }, {
+                    key: 'bindDataSource',
+                    value: function bindDataSource(loader) {
+                        loader.onDataArrival = this.parseChunks.bind(this);
+                        return this;
+                    }
+
+                    // prototype: function(type: string, metadata: any): void
+
+                }, {
+                    key: 'resetMediaInfo',
+                    value: function resetMediaInfo() {
+                        this._mediaInfo = new _mediaInfo2.default();
+                    }
+                }, {
+                    key: '_isInitialMetadataDispatched',
+                    value: function _isInitialMetadataDispatched() {
+                        if (this._hasAudio && this._hasVideo) {
+                            // both audio & video
+                            return this._audioInitialMetadataDispatched && this._videoInitialMetadataDispatched;
+                        }
+                        if (this._hasAudio && !this._hasVideo) {
+                            // audio only
+                            return this._audioInitialMetadataDispatched;
+                        }
+                        if (!this._hasAudio && this._hasVideo) {
+                            // video only
+                            return this._videoInitialMetadataDispatched;
+                        }
+                        return false;
+                    }
+
+                    // function parseChunks(chunk: ArrayBuffer, byteStart: number): number;
+
+                }, {
+                    key: 'parseChunks',
+                    value: function parseChunks(chunk, byteStart) {
+                        if (!this._onError || !this._onMediaInfo || !this._onTrackMetadata || !this._onDataAvailable) {
+                            throw new _exception.IllegalStateException('Flv: onError & onMediaInfo & onTrackMetadata & onDataAvailable callback must be specified');
+                        }
+
+                        var offset = 0;
+                        var le = this._littleEndian;
+
+                        if (byteStart === 0) {
+                            // buffer with FLV header
+                            if (chunk.byteLength > 13) {
+                                var probeData = FLVDemuxer.probe(chunk);
+                                offset = probeData.dataOffset;
+                            } else {
+                                return 0;
+                            }
+                        }
+
+                        if (this._firstParse) {
+                            // handle PreviousTagSize0 before Tag1
+                            this._firstParse = false;
+                            if (byteStart + offset !== this._dataOffset) {
+                                _logger2.default.w(this.TAG, 'First time parsing but chunk byteStart invalid!');
+                            }
+
+                            var v = new DataView(chunk, offset);
+                            var prevTagSize0 = v.getUint32(0, !le);
+                            if (prevTagSize0 !== 0) {
+                                _logger2.default.w(this.TAG, 'PrevTagSize0 !== 0 !!!');
+                            }
                             offset += 4;
-                            for (var i = 0; i < strictArrayLength; i++) {
-                                var val = AMF.parseValue(arrayBuffer, dataOffset + offset, dataSize - offset);
-                                value.push(val.data);
-                                offset += val.size;
+                        }
+
+                        while (offset < chunk.byteLength) {
+                            this._dispatch = true;
+
+                            var _v = new DataView(chunk, offset);
+
+                            if (offset + 11 + 4 > chunk.byteLength) {
+                                // data not enough for parsing an flv tag
+                                break;
                             }
-                            break;
+
+                            var tagType = _v.getUint8(0);
+                            var dataSize = _v.getUint32(0, !le) & 0x00FFFFFF;
+
+                            if (offset + 11 + dataSize + 4 > chunk.byteLength) {
+                                // data not enough for parsing actual data body
+                                break;
+                            }
+
+                            if (tagType !== 8 && tagType !== 9 && tagType !== 18) {
+                                _logger2.default.w(this.TAG, 'Unsupported tag type ' + tagType + ', skipped');
+                                // consume the whole tag (skip it)
+                                offset += 11 + dataSize + 4;
+                                continue;
+                            }
+
+                            var ts2 = _v.getUint8(4);
+                            var ts1 = _v.getUint8(5);
+                            var ts0 = _v.getUint8(6);
+                            var ts3 = _v.getUint8(7);
+
+                            var timestamp = ts0 | ts1 << 8 | ts2 << 16 | ts3 << 24;
+
+                            var streamId = _v.getUint32(7, !le) & 0x00FFFFFF;
+                            if (streamId !== 0) {
+                                _logger2.default.w(this.TAG, 'Meet tag which has StreamID != 0!');
+                            }
+
+                            var dataOffset = offset + 11;
+
+                            switch (tagType) {
+                                case 8:
+                                    // Audio
+                                    this._parseAudioData(chunk, dataOffset, dataSize, timestamp);
+                                    break;
+                                case 9:
+                                    // Video
+                                    this._parseVideoData(chunk, dataOffset, dataSize, timestamp, byteStart + offset);
+                                    break;
+                                case 18:
+                                    // ScriptDataObject
+                                    this._parseScriptData(chunk, dataOffset, dataSize);
+                                    break;
+                            }
+
+                            var prevTagSize = _v.getUint32(11 + dataSize, !le);
+                            if (prevTagSize !== 11 + dataSize) {
+                                _logger2.default.w(this.TAG, 'Invalid PrevTagSize ' + prevTagSize);
+                            }
+
+                            offset += 11 + dataSize + 4; // tagBody + dataSize + prevTagSize
                         }
-                    case 11:
-                        {
-                            // Date type
-                            var date = AMF.parseDate(arrayBuffer, dataOffset + 1, dataSize - 1);
-                            value = date.data;
-                            offset += date.size;
-                            break;
+
+                        // dispatch parsed frames to consumer (typically, the remuxer)
+                        if (this._isInitialMetadataDispatched()) {
+                            if (this._dispatch && (this._audioTrack.length || this._videoTrack.length)) {
+                                this._onDataAvailable(this._audioTrack, this._videoTrack);
+                            }
                         }
-                    case 12:
-                        {
-                            // Long string type
-                            var amfLongStr = AMF.parseString(arrayBuffer, dataOffset + 1, dataSize - 1);
-                            value = amfLongStr.data;
-                            offset += amfLongStr.size;
-                            break;
-                        }
-                    default:
-                        // ignore and skip
-                        offset = dataSize;
-                        _logger2.default.w('AMF', 'Unsupported AMF value type ' + type);
-                }
-            } catch (e) {
-                _logger2.default.e('AMF', e.toString());
-            }
 
-            return {
-                data: value,
-                size: offset,
-                objectEnd: objectEnd
-            };
-        }
-    }]);
-
-    return AMF;
-}();
-
-exports.default = AMF;
-
-},{"../utils/exception.js":40,"../utils/logger.js":41,"../utils/utf8-conv.js":44}],16:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var DemuxErrors = {
-  OK: 'OK',
-  FORMAT_ERROR: 'FormatError',
-  FORMAT_UNSUPPORTED: 'FormatUnsupported',
-  CODEC_UNSUPPORTED: 'CodecUnsupported'
-};
-
-exports.default = DemuxErrors;
-
-},{}],17:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
-
-var _exception = _dereq_('../utils/exception.js');
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-// Exponential-Golomb buffer decoder
-var ExpGolomb = function () {
-    function ExpGolomb(uint8array) {
-        _classCallCheck(this, ExpGolomb);
-
-        this.TAG = 'ExpGolomb';
-
-        this._buffer = uint8array;
-        this._buffer_index = 0;
-        this._total_bytes = uint8array.byteLength;
-        this._total_bits = uint8array.byteLength * 8;
-        this._current_word = 0;
-        this._current_word_bits_left = 0;
-    }
-
-    _createClass(ExpGolomb, [{
-        key: 'destroy',
-        value: function destroy() {
-            this._buffer = null;
-        }
-    }, {
-        key: '_fillCurrentWord',
-        value: function _fillCurrentWord() {
-            var buffer_bytes_left = this._total_bytes - this._buffer_index;
-            if (buffer_bytes_left <= 0) throw new _exception.IllegalStateException('ExpGolomb: _fillCurrentWord() but no bytes available');
-
-            var bytes_read = Math.min(4, buffer_bytes_left);
-            var word = new Uint8Array(4);
-            word.set(this._buffer.subarray(this._buffer_index, this._buffer_index + bytes_read));
-            this._current_word = new DataView(word.buffer).getUint32(0, false);
-
-            this._buffer_index += bytes_read;
-            this._current_word_bits_left = bytes_read * 8;
-        }
-    }, {
-        key: 'readBits',
-        value: function readBits(bits) {
-            if (bits > 32) throw new _exception.InvalidArgumentException('ExpGolomb: readBits() bits exceeded max 32bits!');
-
-            if (bits <= this._current_word_bits_left) {
-                var _result = this._current_word >>> 32 - bits;
-                this._current_word <<= bits;
-                this._current_word_bits_left -= bits;
-                return _result;
-            }
-
-            var result = this._current_word_bits_left ? this._current_word : 0;
-            result = result >>> 32 - this._current_word_bits_left;
-            var bits_need_left = bits - this._current_word_bits_left;
-
-            this._fillCurrentWord();
-            var bits_read_next = Math.min(bits_need_left, this._current_word_bits_left);
-
-            var result2 = this._current_word >>> 32 - bits_read_next;
-            this._current_word <<= bits_read_next;
-            this._current_word_bits_left -= bits_read_next;
-
-            result = result << bits_read_next | result2;
-            return result;
-        }
-    }, {
-        key: 'readBool',
-        value: function readBool() {
-            return this.readBits(1) === 1;
-        }
-    }, {
-        key: 'readByte',
-        value: function readByte() {
-            return this.readBits(8);
-        }
-    }, {
-        key: '_skipLeadingZero',
-        value: function _skipLeadingZero() {
-            var zero_count = void 0;
-            for (zero_count = 0; zero_count < this._current_word_bits_left; zero_count++) {
-                if (0 !== (this._current_word & 0x80000000 >>> zero_count)) {
-                    this._current_word <<= zero_count;
-                    this._current_word_bits_left -= zero_count;
-                    return zero_count;
-                }
-            }
-            this._fillCurrentWord();
-            return zero_count + this._skipLeadingZero();
-        }
-    }, {
-        key: 'readUEG',
-        value: function readUEG() {
-            // unsigned exponential golomb
-            var leading_zeros = this._skipLeadingZero();
-            return this.readBits(leading_zeros + 1) - 1;
-        }
-    }, {
-        key: 'readSEG',
-        value: function readSEG() {
-            // signed exponential golomb
-            var value = this.readUEG();
-            if (value & 0x01) {
-                return value + 1 >>> 1;
-            } else {
-                return -1 * (value >>> 1);
-            }
-        }
-    }]);
-
-    return ExpGolomb;
-}();
-
-exports.default = ExpGolomb;
-
-},{"../utils/exception.js":40}],18:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; };
-
-var _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; }; }(); /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _amfParser = _dereq_('./amf-parser.js');
-
-var _amfParser2 = _interopRequireDefault(_amfParser);
-
-var _spsParser = _dereq_('./sps-parser.js');
-
-var _spsParser2 = _interopRequireDefault(_spsParser);
-
-var _demuxErrors = _dereq_('./demux-errors.js');
-
-var _demuxErrors2 = _interopRequireDefault(_demuxErrors);
-
-var _mediaInfo = _dereq_('../core/media-info.js');
-
-var _mediaInfo2 = _interopRequireDefault(_mediaInfo);
-
-var _exception = _dereq_('../utils/exception.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function Swap16(src) {
-    return src >>> 8 & 0xFF | (src & 0xFF) << 8;
-}
-
-function Swap32(src) {
-    return (src & 0xFF000000) >>> 24 | (src & 0x00FF0000) >>> 8 | (src & 0x0000FF00) << 8 | (src & 0x000000FF) << 24;
-}
-
-function ReadBig32(array, index) {
-    return array[index] << 24 | array[index + 1] << 16 | array[index + 2] << 8 | array[index + 3];
-}
-
-var FLVDemuxer = function () {
-    function FLVDemuxer(probeData, config) {
-        _classCallCheck(this, FLVDemuxer);
-
-        this.TAG = 'FLVDemuxer';
-
-        this._config = config;
-
-        this._onError = null;
-        this._onMediaInfo = null;
-        this._onMetaDataArrived = null;
-        this._onScriptDataArrived = null;
-        this._onTrackMetadata = null;
-        this._onDataAvailable = null;
-
-        this._dataOffset = probeData.dataOffset;
-        this._firstParse = true;
-        this._dispatch = false;
-
-        this._hasAudio = probeData.hasAudioTrack;
-        this._hasVideo = probeData.hasVideoTrack;
-
-        this._hasAudioFlagOverrided = false;
-        this._hasVideoFlagOverrided = false;
-
-        this._audioInitialMetadataDispatched = false;
-        this._videoInitialMetadataDispatched = false;
-
-        this._mediaInfo = new _mediaInfo2.default();
-        this._mediaInfo.hasAudio = this._hasAudio;
-        this._mediaInfo.hasVideo = this._hasVideo;
-        this._metadata = null;
-        this._audioMetadata = null;
-        this._videoMetadata = null;
-
-        this._naluLengthSize = 4;
-        this._timestampBase = 0; // int32, in milliseconds
-        this._timescale = 1000;
-        this._duration = 0; // int32, in milliseconds
-        this._durationOverrided = false;
-        this._referenceFrameRate = {
-            fixed: true,
-            fps: 23.976,
-            fps_num: 23976,
-            fps_den: 1000
-        };
-
-        this._flvSoundRateTable = [5500, 11025, 22050, 44100, 48000];
-
-        this._mpegSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
-
-        this._mpegAudioV10SampleRateTable = [44100, 48000, 32000, 0];
-        this._mpegAudioV20SampleRateTable = [22050, 24000, 16000, 0];
-        this._mpegAudioV25SampleRateTable = [11025, 12000, 8000, 0];
-
-        this._mpegAudioL1BitRateTable = [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1];
-        this._mpegAudioL2BitRateTable = [0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1];
-        this._mpegAudioL3BitRateTable = [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1];
-
-        this._videoTrack = { type: 'video', id: 1, sequenceNumber: 0, samples: [], length: 0 };
-        this._audioTrack = { type: 'audio', id: 2, sequenceNumber: 0, samples: [], length: 0 };
-
-        this._littleEndian = function () {
-            var buf = new ArrayBuffer(2);
-            new DataView(buf).setInt16(0, 256, true); // little-endian write
-            return new Int16Array(buf)[0] === 256; // platform-spec read, if equal then LE
-        }();
-    }
-
-    _createClass(FLVDemuxer, [{
-        key: 'destroy',
-        value: function destroy() {
-            this._mediaInfo = null;
-            this._metadata = null;
-            this._audioMetadata = null;
-            this._videoMetadata = null;
-            this._videoTrack = null;
-            this._audioTrack = null;
-
-            this._onError = null;
-            this._onMediaInfo = null;
-            this._onMetaDataArrived = null;
-            this._onScriptDataArrived = null;
-            this._onTrackMetadata = null;
-            this._onDataAvailable = null;
-        }
-    }, {
-        key: 'bindDataSource',
-        value: function bindDataSource(loader) {
-            loader.onDataArrival = this.parseChunks.bind(this);
-            return this;
-        }
-
-        // prototype: function(type: string, metadata: any): void
-
-    }, {
-        key: 'resetMediaInfo',
-        value: function resetMediaInfo() {
-            this._mediaInfo = new _mediaInfo2.default();
-        }
-    }, {
-        key: '_isInitialMetadataDispatched',
-        value: function _isInitialMetadataDispatched() {
-            if (this._hasAudio && this._hasVideo) {
-                // both audio & video
-                return this._audioInitialMetadataDispatched && this._videoInitialMetadataDispatched;
-            }
-            if (this._hasAudio && !this._hasVideo) {
-                // audio only
-                return this._audioInitialMetadataDispatched;
-            }
-            if (!this._hasAudio && this._hasVideo) {
-                // video only
-                return this._videoInitialMetadataDispatched;
-            }
-            return false;
-        }
-
-        // function parseChunks(chunk: ArrayBuffer, byteStart: number): number;
-
-    }, {
-        key: 'parseChunks',
-        value: function parseChunks(chunk, byteStart) {
-            if (!this._onError || !this._onMediaInfo || !this._onTrackMetadata || !this._onDataAvailable) {
-                throw new _exception.IllegalStateException('Flv: onError & onMediaInfo & onTrackMetadata & onDataAvailable callback must be specified');
-            }
-
-            var offset = 0;
-            var le = this._littleEndian;
-
-            if (byteStart === 0) {
-                // buffer with FLV header
-                if (chunk.byteLength > 13) {
-                    var probeData = FLVDemuxer.probe(chunk);
-                    offset = probeData.dataOffset;
-                } else {
-                    return 0;
-                }
-            }
-
-            if (this._firstParse) {
-                // handle PreviousTagSize0 before Tag1
-                this._firstParse = false;
-                if (byteStart + offset !== this._dataOffset) {
-                    _logger2.default.w(this.TAG, 'First time parsing but chunk byteStart invalid!');
-                }
-
-                var v = new DataView(chunk, offset);
-                var prevTagSize0 = v.getUint32(0, !le);
-                if (prevTagSize0 !== 0) {
-                    _logger2.default.w(this.TAG, 'PrevTagSize0 !== 0 !!!');
-                }
-                offset += 4;
-            }
-
-            while (offset < chunk.byteLength) {
-                this._dispatch = true;
-
-                var _v = new DataView(chunk, offset);
-
-                if (offset + 11 + 4 > chunk.byteLength) {
-                    // data not enough for parsing an flv tag
-                    break;
-                }
-
-                var tagType = _v.getUint8(0);
-                var dataSize = _v.getUint32(0, !le) & 0x00FFFFFF;
-
-                if (offset + 11 + dataSize + 4 > chunk.byteLength) {
-                    // data not enough for parsing actual data body
-                    break;
-                }
-
-                if (tagType !== 8 && tagType !== 9 && tagType !== 18) {
-                    _logger2.default.w(this.TAG, 'Unsupported tag type ' + tagType + ', skipped');
-                    // consume the whole tag (skip it)
-                    offset += 11 + dataSize + 4;
-                    continue;
-                }
-
-                var ts2 = _v.getUint8(4);
-                var ts1 = _v.getUint8(5);
-                var ts0 = _v.getUint8(6);
-                var ts3 = _v.getUint8(7);
-
-                var timestamp = ts0 | ts1 << 8 | ts2 << 16 | ts3 << 24;
-
-                var streamId = _v.getUint32(7, !le) & 0x00FFFFFF;
-                if (streamId !== 0) {
-                    _logger2.default.w(this.TAG, 'Meet tag which has StreamID != 0!');
-                }
-
-                var dataOffset = offset + 11;
-
-                switch (tagType) {
-                    case 8:
-                        // Audio
-                        this._parseAudioData(chunk, dataOffset, dataSize, timestamp);
-                        break;
-                    case 9:
-                        // Video
-                        this._parseVideoData(chunk, dataOffset, dataSize, timestamp, byteStart + offset);
-                        break;
-                    case 18:
-                        // ScriptDataObject
-                        this._parseScriptData(chunk, dataOffset, dataSize);
-                        break;
-                }
-
-                var prevTagSize = _v.getUint32(11 + dataSize, !le);
-                if (prevTagSize !== 11 + dataSize) {
-                    _logger2.default.w(this.TAG, 'Invalid PrevTagSize ' + prevTagSize);
-                }
-
-                offset += 11 + dataSize + 4; // tagBody + dataSize + prevTagSize
-            }
-
-            // dispatch parsed frames to consumer (typically, the remuxer)
-            if (this._isInitialMetadataDispatched()) {
-                if (this._dispatch && (this._audioTrack.length || this._videoTrack.length)) {
-                    this._onDataAvailable(this._audioTrack, this._videoTrack);
-                }
-            }
-
-            return offset; // consumed bytes, just equals latest offset index
-        }
-    }, {
-        key: '_parseScriptData',
-        value: function _parseScriptData(arrayBuffer, dataOffset, dataSize) {
-            var scriptData = _amfParser2.default.parseScriptData(arrayBuffer, dataOffset, dataSize);
-
-            if (scriptData.hasOwnProperty('onMetaData')) {
-                if (scriptData.onMetaData == null || _typeof(scriptData.onMetaData) !== 'object') {
-                    _logger2.default.w(this.TAG, 'Invalid onMetaData structure!');
-                    return;
-                }
-                if (this._metadata) {
-                    _logger2.default.w(this.TAG, 'Found another onMetaData tag!');
-                }
-                this._metadata = scriptData;
-                var onMetaData = this._metadata.onMetaData;
-
-                if (this._onMetaDataArrived) {
-                    this._onMetaDataArrived(Object.assign({}, onMetaData));
-                }
-
-                if (typeof onMetaData.hasAudio === 'boolean') {
-                    // hasAudio
-                    if (this._hasAudioFlagOverrided === false) {
-                        this._hasAudio = onMetaData.hasAudio;
-                        this._mediaInfo.hasAudio = this._hasAudio;
+                        return offset; // consumed bytes, just equals latest offset index
                     }
-                }
-                if (typeof onMetaData.hasVideo === 'boolean') {
-                    // hasVideo
-                    if (this._hasVideoFlagOverrided === false) {
-                        this._hasVideo = onMetaData.hasVideo;
-                        this._mediaInfo.hasVideo = this._hasVideo;
+                }, {
+                    key: '_parseScriptData',
+                    value: function _parseScriptData(arrayBuffer, dataOffset, dataSize) {
+                        var scriptData = _amfParser2.default.parseScriptData(arrayBuffer, dataOffset, dataSize);
+
+                        if (scriptData.hasOwnProperty('onMetaData')) {
+                            if (scriptData.onMetaData == null || _typeof(scriptData.onMetaData) !== 'object') {
+                                _logger2.default.w(this.TAG, 'Invalid onMetaData structure!');
+                                return;
+                            }
+                            if (this._metadata) {
+                                _logger2.default.w(this.TAG, 'Found another onMetaData tag!');
+                            }
+                            this._metadata = scriptData;
+                            var onMetaData = this._metadata.onMetaData;
+
+                            if (this._onMetaDataArrived) {
+                                this._onMetaDataArrived(Object.assign({}, onMetaData));
+                            }
+
+                            if (typeof onMetaData.hasAudio === 'boolean') {
+                                // hasAudio
+                                if (this._hasAudioFlagOverrided === false) {
+                                    this._hasAudio = onMetaData.hasAudio;
+                                    this._mediaInfo.hasAudio = this._hasAudio;
+                                }
+                            }
+                            if (typeof onMetaData.hasVideo === 'boolean') {
+                                // hasVideo
+                                if (this._hasVideoFlagOverrided === false) {
+                                    this._hasVideo = onMetaData.hasVideo;
+                                    this._mediaInfo.hasVideo = this._hasVideo;
+                                }
+                            }
+                            if (typeof onMetaData.audiodatarate === 'number') {
+                                // audiodatarate
+                                this._mediaInfo.audioDataRate = onMetaData.audiodatarate;
+                            }
+                            if (typeof onMetaData.videodatarate === 'number') {
+                                // videodatarate
+                                this._mediaInfo.videoDataRate = onMetaData.videodatarate;
+                            }
+                            if (typeof onMetaData.width === 'number') {
+                                // width
+                                this._mediaInfo.width = onMetaData.width;
+                            }
+                            if (typeof onMetaData.height === 'number') {
+                                // height
+                                this._mediaInfo.height = onMetaData.height;
+                            }
+                            if (typeof onMetaData.duration === 'number') {
+                                // duration
+                                if (!this._durationOverrided) {
+                                    var duration = Math.floor(onMetaData.duration * this._timescale);
+                                    this._duration = duration;
+                                    this._mediaInfo.duration = duration;
+                                }
+                            } else {
+                                this._mediaInfo.duration = 0;
+                            }
+                            if (typeof onMetaData.framerate === 'number') {
+                                // framerate
+                                var fps_num = Math.floor(onMetaData.framerate * 1000);
+                                if (fps_num > 0) {
+                                    var fps = fps_num / 1000;
+                                    this._referenceFrameRate.fixed = true;
+                                    this._referenceFrameRate.fps = fps;
+                                    this._referenceFrameRate.fps_num = fps_num;
+                                    this._referenceFrameRate.fps_den = 1000;
+                                    this._mediaInfo.fps = fps;
+                                }
+                            }
+                            if (_typeof(onMetaData.keyframes) === 'object') {
+                                // keyframes
+                                this._mediaInfo.hasKeyframesIndex = true;
+                                var keyframes = onMetaData.keyframes;
+                                this._mediaInfo.keyframesIndex = this._parseKeyframesIndex(keyframes);
+                                onMetaData.keyframes = null; // keyframes has been extracted, remove it
+                            } else {
+                                this._mediaInfo.hasKeyframesIndex = false;
+                            }
+                            this._dispatch = false;
+                            this._mediaInfo.metadata = onMetaData;
+                            _logger2.default.v(this.TAG, 'Parsed onMetaData');
+                            if (this._mediaInfo.isComplete()) {
+                                this._onMediaInfo(this._mediaInfo);
+                            }
+                        }
+
+                        if (Object.keys(scriptData).length > 0) {
+                            if (this._onScriptDataArrived) {
+                                this._onScriptDataArrived(Object.assign({}, scriptData));
+                            }
+                        }
                     }
-                }
-                if (typeof onMetaData.audiodatarate === 'number') {
-                    // audiodatarate
-                    this._mediaInfo.audioDataRate = onMetaData.audiodatarate;
-                }
-                if (typeof onMetaData.videodatarate === 'number') {
-                    // videodatarate
-                    this._mediaInfo.videoDataRate = onMetaData.videodatarate;
-                }
-                if (typeof onMetaData.width === 'number') {
-                    // width
-                    this._mediaInfo.width = onMetaData.width;
-                }
-                if (typeof onMetaData.height === 'number') {
-                    // height
-                    this._mediaInfo.height = onMetaData.height;
-                }
-                if (typeof onMetaData.duration === 'number') {
-                    // duration
-                    if (!this._durationOverrided) {
-                        var duration = Math.floor(onMetaData.duration * this._timescale);
+                }, {
+                    key: '_parseKeyframesIndex',
+                    value: function _parseKeyframesIndex(keyframes) {
+                        var times = [];
+                        var filepositions = [];
+
+                        // ignore first keyframe which is actually AVC Sequence Header (AVCDecoderConfigurationRecord)
+                        for (var i = 1; i < keyframes.times.length; i++) {
+                            var time = this._timestampBase + Math.floor(keyframes.times[i] * 1000);
+                            times.push(time);
+                            filepositions.push(keyframes.filepositions[i]);
+                        }
+
+                        return {
+                            times: times,
+                            filepositions: filepositions
+                        };
+                    }
+                }, {
+                    key: '_parseAudioData',
+                    value: function _parseAudioData(arrayBuffer, dataOffset, dataSize, tagTimestamp) {
+                        if (dataSize <= 1) {
+                            _logger2.default.w(this.TAG, 'Flv: Invalid audio packet, missing SoundData payload!');
+                            return;
+                        }
+
+                        if (this._hasAudioFlagOverrided === true && this._hasAudio === false) {
+                            // If hasAudio: false indicated explicitly in MediaDataSource,
+                            // Ignore all the audio packets
+                            return;
+                        }
+
+                        var le = this._littleEndian;
+                        var v = new DataView(arrayBuffer, dataOffset, dataSize);
+
+                        var soundSpec = v.getUint8(0);
+
+                        var soundFormat = soundSpec >>> 4;
+                        if (soundFormat !== 2 && soundFormat !== 10) {
+                            // MP3 or AAC
+                            this._onError(_demuxErrors2.default.CODEC_UNSUPPORTED, 'Flv: Unsupported audio codec idx: ' + soundFormat);
+                            return;
+                        }
+
+                        var soundRate = 0;
+                        var soundRateIndex = (soundSpec & 12) >>> 2;
+                        if (soundRateIndex >= 0 && soundRateIndex <= 4) {
+                            soundRate = this._flvSoundRateTable[soundRateIndex];
+                        } else {
+                            this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid audio sample rate idx: ' + soundRateIndex);
+                            return;
+                        }
+
+                        var soundSize = (soundSpec & 2) >>> 1; // unused
+                        var soundType = soundSpec & 1;
+
+                        var meta = this._audioMetadata;
+                        var track = this._audioTrack;
+
+                        if (!meta) {
+                            if (this._hasAudio === false && this._hasAudioFlagOverrided === false) {
+                                this._hasAudio = true;
+                                this._mediaInfo.hasAudio = true;
+                            }
+
+                            // initial metadata
+                            meta = this._audioMetadata = {};
+                            meta.type = 'audio';
+                            meta.id = track.id;
+                            meta.timescale = this._timescale;
+                            meta.duration = this._duration;
+                            meta.audioSampleRate = soundRate;
+                            meta.channelCount = soundType === 0 ? 1 : 2;
+                        }
+
+                        if (soundFormat === 10) {
+                            // AAC
+                            var aacData = this._parseAACAudioData(arrayBuffer, dataOffset + 1, dataSize - 1);
+                            if (aacData == undefined) {
+                                return;
+                            }
+
+                            if (aacData.packetType === 0) {
+                                // AAC sequence header (AudioSpecificConfig)
+                                if (meta.config) {
+                                    _logger2.default.w(this.TAG, 'Found another AudioSpecificConfig!');
+                                }
+                                var misc = aacData.data;
+                                meta.audioSampleRate = misc.samplingRate;
+                                meta.channelCount = misc.channelCount;
+                                meta.codec = misc.codec;
+                                meta.originalCodec = misc.originalCodec;
+                                meta.config = misc.config;
+                                // The decode result of an aac sample is 1024 PCM samples
+                                meta.refSampleDuration = 1024 / meta.audioSampleRate * meta.timescale;
+                                _logger2.default.v(this.TAG, 'Parsed AudioSpecificConfig');
+
+                                if (this._isInitialMetadataDispatched()) {
+                                    // Non-initial metadata, force dispatch (or flush) parsed frames to remuxer
+                                    if (this._dispatch && (this._audioTrack.length || this._videoTrack.length)) {
+                                        this._onDataAvailable(this._audioTrack, this._videoTrack);
+                                    }
+                                } else {
+                                    this._audioInitialMetadataDispatched = true;
+                                }
+                                // then notify new metadata
+                                this._dispatch = false;
+                                this._onTrackMetadata('audio', meta);
+
+                                var mi = this._mediaInfo;
+                                mi.audioCodec = meta.originalCodec;
+                                mi.audioSampleRate = meta.audioSampleRate;
+                                mi.audioChannelCount = meta.channelCount;
+                                if (mi.hasVideo) {
+                                    if (mi.videoCodec != null) {
+                                        mi.mimeType = 'video/x-flv; codecs="' + mi.videoCodec + ',' + mi.audioCodec + '"';
+                                    }
+                                } else {
+                                    mi.mimeType = 'video/x-flv; codecs="' + mi.audioCodec + '"';
+                                }
+                                if (mi.isComplete()) {
+                                    this._onMediaInfo(mi);
+                                }
+                            } else if (aacData.packetType === 1) {
+                                // AAC raw frame data
+                                var dts = this._timestampBase + tagTimestamp;
+                                var aacSample = { unit: aacData.data, length: aacData.data.byteLength, dts: dts, pts: dts };
+                                track.samples.push(aacSample);
+                                track.length += aacData.data.length;
+                            } else {
+                                _logger2.default.e(this.TAG, 'Flv: Unsupported AAC data type ' + aacData.packetType);
+                            }
+                        } else if (soundFormat === 2) {
+                            // MP3
+                            if (!meta.codec) {
+                                // We need metadata for mp3 audio track, extract info from frame header
+                                var _misc = this._parseMP3AudioData(arrayBuffer, dataOffset + 1, dataSize - 1, true);
+                                if (_misc == undefined) {
+                                    return;
+                                }
+                                meta.audioSampleRate = _misc.samplingRate;
+                                meta.channelCount = _misc.channelCount;
+                                meta.codec = _misc.codec;
+                                meta.originalCodec = _misc.originalCodec;
+                                // The decode result of an mp3 sample is 1152 PCM samples
+                                meta.refSampleDuration = 1152 / meta.audioSampleRate * meta.timescale;
+                                _logger2.default.v(this.TAG, 'Parsed MPEG Audio Frame Header');
+
+                                this._audioInitialMetadataDispatched = true;
+                                this._onTrackMetadata('audio', meta);
+
+                                var _mi = this._mediaInfo;
+                                _mi.audioCodec = meta.codec;
+                                _mi.audioSampleRate = meta.audioSampleRate;
+                                _mi.audioChannelCount = meta.channelCount;
+                                _mi.audioDataRate = _misc.bitRate;
+                                if (_mi.hasVideo) {
+                                    if (_mi.videoCodec != null) {
+                                        _mi.mimeType = 'video/x-flv; codecs="' + _mi.videoCodec + ',' + _mi.audioCodec + '"';
+                                    }
+                                } else {
+                                    _mi.mimeType = 'video/x-flv; codecs="' + _mi.audioCodec + '"';
+                                }
+                                if (_mi.isComplete()) {
+                                    this._onMediaInfo(_mi);
+                                }
+                            }
+
+                            // This packet is always a valid audio packet, extract it
+                            var data = this._parseMP3AudioData(arrayBuffer, dataOffset + 1, dataSize - 1, false);
+                            if (data == undefined) {
+                                return;
+                            }
+                            var _dts = this._timestampBase + tagTimestamp;
+                            var mp3Sample = { unit: data, length: data.byteLength, dts: _dts, pts: _dts };
+                            track.samples.push(mp3Sample);
+                            track.length += data.length;
+                        }
+                    }
+                }, {
+                    key: '_parseAACAudioData',
+                    value: function _parseAACAudioData(arrayBuffer, dataOffset, dataSize) {
+                        if (dataSize <= 1) {
+                            _logger2.default.w(this.TAG, 'Flv: Invalid AAC packet, missing AACPacketType or/and Data!');
+                            return;
+                        }
+
+                        var result = {};
+                        var array = new Uint8Array(arrayBuffer, dataOffset, dataSize);
+
+                        result.packetType = array[0];
+
+                        if (array[0] === 0) {
+                            result.data = this._parseAACAudioSpecificConfig(arrayBuffer, dataOffset + 1, dataSize - 1);
+                        } else {
+                            result.data = array.subarray(1);
+                        }
+
+                        return result;
+                    }
+                }, {
+                    key: '_parseAACAudioSpecificConfig',
+                    value: function _parseAACAudioSpecificConfig(arrayBuffer, dataOffset, dataSize) {
+                        var array = new Uint8Array(arrayBuffer, dataOffset, dataSize);
+                        var config = null;
+
+                        /* Audio Object Type:
+                           0: Null
+                           1: AAC Main
+                           2: AAC LC
+                           3: AAC SSR (Scalable Sample Rate)
+                           4: AAC LTP (Long Term Prediction)
+                           5: HE-AAC / SBR (Spectral Band Replication)
+                           6: AAC Scalable
+                        */
+
+                        var audioObjectType = 0;
+                        var originalAudioObjectType = 0;
+                        var audioExtensionObjectType = null;
+                        var samplingIndex = 0;
+                        var extensionSamplingIndex = null;
+
+                        // 5 bits
+                        audioObjectType = originalAudioObjectType = array[0] >>> 3;
+                        // 4 bits
+                        samplingIndex = (array[0] & 0x07) << 1 | array[1] >>> 7;
+                        if (samplingIndex < 0 || samplingIndex >= this._mpegSamplingRates.length) {
+                            this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: AAC invalid sampling frequency index!');
+                            return;
+                        }
+
+                        var samplingFrequence = this._mpegSamplingRates[samplingIndex];
+
+                        // 4 bits
+                        var channelConfig = (array[1] & 0x78) >>> 3;
+                        if (channelConfig < 0 || channelConfig >= 8) {
+                            this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: AAC invalid channel configuration');
+                            return;
+                        }
+
+                        if (audioObjectType === 5) {
+                            // HE-AAC?
+                            // 4 bits
+                            extensionSamplingIndex = (array[1] & 0x07) << 1 | array[2] >>> 7;
+                            // 5 bits
+                            audioExtensionObjectType = (array[2] & 0x7C) >>> 2;
+                        }
+
+                        // workarounds for various browsers
+                        var userAgent = self.navigator.userAgent.toLowerCase();
+
+                        if (userAgent.indexOf('firefox') !== -1) {
+                            // firefox: use SBR (HE-AAC) if freq less than 24kHz
+                            if (samplingIndex >= 6) {
+                                audioObjectType = 5;
+                                config = new Array(4);
+                                extensionSamplingIndex = samplingIndex - 3;
+                            } else {
+                                // use LC-AAC
+                                audioObjectType = 2;
+                                config = new Array(2);
+                                extensionSamplingIndex = samplingIndex;
+                            }
+                        } else if (userAgent.indexOf('android') !== -1) {
+                            // android: always use LC-AAC
+                            audioObjectType = 2;
+                            config = new Array(2);
+                            extensionSamplingIndex = samplingIndex;
+                        } else {
+                            // for other browsers, e.g. chrome...
+                            // Always use HE-AAC to make it easier to switch aac codec profile
+                            audioObjectType = 5;
+                            extensionSamplingIndex = samplingIndex;
+                            config = new Array(4);
+
+                            if (samplingIndex >= 6) {
+                                extensionSamplingIndex = samplingIndex - 3;
+                            } else if (channelConfig === 1) {
+                                // Mono channel
+                                audioObjectType = 2;
+                                config = new Array(2);
+                                extensionSamplingIndex = samplingIndex;
+                            }
+                        }
+
+                        config[0] = audioObjectType << 3;
+                        config[0] |= (samplingIndex & 0x0F) >>> 1;
+                        config[1] = (samplingIndex & 0x0F) << 7;
+                        config[1] |= (channelConfig & 0x0F) << 3;
+                        if (audioObjectType === 5) {
+                            config[1] |= (extensionSamplingIndex & 0x0F) >>> 1;
+                            config[2] = (extensionSamplingIndex & 0x01) << 7;
+                            // extended audio object type: force to 2 (LC-AAC)
+                            config[2] |= 2 << 2;
+                            config[3] = 0;
+                        }
+
+                        return {
+                            config: config,
+                            samplingRate: samplingFrequence,
+                            channelCount: channelConfig,
+                            codec: 'mp4a.40.' + audioObjectType,
+                            originalCodec: 'mp4a.40.' + originalAudioObjectType
+                        };
+                    }
+                }, {
+                    key: '_parseMP3AudioData',
+                    value: function _parseMP3AudioData(arrayBuffer, dataOffset, dataSize, requestHeader) {
+                        if (dataSize < 4) {
+                            _logger2.default.w(this.TAG, 'Flv: Invalid MP3 packet, header missing!');
+                            return;
+                        }
+
+                        var le = this._littleEndian;
+                        var array = new Uint8Array(arrayBuffer, dataOffset, dataSize);
+                        var result = null;
+
+                        if (requestHeader) {
+                            if (array[0] !== 0xFF) {
+                                return;
+                            }
+                            var ver = array[1] >>> 3 & 0x03;
+                            var layer = (array[1] & 0x06) >> 1;
+
+                            var bitrate_index = (array[2] & 0xF0) >>> 4;
+                            var sampling_freq_index = (array[2] & 0x0C) >>> 2;
+
+                            var channel_mode = array[3] >>> 6 & 0x03;
+                            var channel_count = channel_mode !== 3 ? 2 : 1;
+
+                            var sample_rate = 0;
+                            var bit_rate = 0;
+                            var object_type = 34; // Layer-3, listed in MPEG-4 Audio Object Types
+
+                            var codec = 'mp3';
+
+                            switch (ver) {
+                                case 0:
+                                    // MPEG 2.5
+                                    sample_rate = this._mpegAudioV25SampleRateTable[sampling_freq_index];
+                                    break;
+                                case 2:
+                                    // MPEG 2
+                                    sample_rate = this._mpegAudioV20SampleRateTable[sampling_freq_index];
+                                    break;
+                                case 3:
+                                    // MPEG 1
+                                    sample_rate = this._mpegAudioV10SampleRateTable[sampling_freq_index];
+                                    break;
+                            }
+
+                            switch (layer) {
+                                case 1:
+                                    // Layer 3
+                                    object_type = 34;
+                                    if (bitrate_index < this._mpegAudioL3BitRateTable.length) {
+                                        bit_rate = this._mpegAudioL3BitRateTable[bitrate_index];
+                                    }
+                                    break;
+                                case 2:
+                                    // Layer 2
+                                    object_type = 33;
+                                    if (bitrate_index < this._mpegAudioL2BitRateTable.length) {
+                                        bit_rate = this._mpegAudioL2BitRateTable[bitrate_index];
+                                    }
+                                    break;
+                                case 3:
+                                    // Layer 1
+                                    object_type = 32;
+                                    if (bitrate_index < this._mpegAudioL1BitRateTable.length) {
+                                        bit_rate = this._mpegAudioL1BitRateTable[bitrate_index];
+                                    }
+                                    break;
+                            }
+
+                            result = {
+                                bitRate: bit_rate,
+                                samplingRate: sample_rate,
+                                channelCount: channel_count,
+                                codec: codec,
+                                originalCodec: codec
+                            };
+                        } else {
+                            result = array;
+                        }
+
+                        return result;
+                    }
+                }, {
+                    key: '_parseVideoData',
+                    value: function _parseVideoData(arrayBuffer, dataOffset, dataSize, tagTimestamp, tagPosition) {
+                        if (dataSize <= 1) {
+                            _logger2.default.w(this.TAG, 'Flv: Invalid video packet, missing VideoData payload!');
+                            return;
+                        }
+
+                        if (this._hasVideoFlagOverrided === true && this._hasVideo === false) {
+                            // If hasVideo: false indicated explicitly in MediaDataSource,
+                            // Ignore all the video packets
+                            return;
+                        }
+
+                        var spec = new Uint8Array(arrayBuffer, dataOffset, dataSize)[0];
+
+                        var frameType = (spec & 240) >>> 4;
+                        var codecId = spec & 15;
+
+                        if (codecId !== 7) {
+                            this._onError(_demuxErrors2.default.CODEC_UNSUPPORTED, 'Flv: Unsupported codec in video frame: ' + codecId);
+                            return;
+                        }
+
+                        this._parseAVCVideoPacket(arrayBuffer, dataOffset + 1, dataSize - 1, tagTimestamp, tagPosition, frameType);
+                    }
+                }, {
+                    key: '_parseAVCVideoPacket',
+                    value: function _parseAVCVideoPacket(arrayBuffer, dataOffset, dataSize, tagTimestamp, tagPosition, frameType) {
+                        if (dataSize < 4) {
+                            _logger2.default.w(this.TAG, 'Flv: Invalid AVC packet, missing AVCPacketType or/and CompositionTime');
+                            return;
+                        }
+
+                        var le = this._littleEndian;
+                        var v = new DataView(arrayBuffer, dataOffset, dataSize);
+
+                        var packetType = v.getUint8(0);
+                        var cts_unsigned = v.getUint32(0, !le) & 0x00FFFFFF;
+                        var cts = cts_unsigned << 8 >> 8; // convert to 24-bit signed int
+
+                        if (packetType === 0) {
+                            // AVCDecoderConfigurationRecord
+                            this._parseAVCDecoderConfigurationRecord(arrayBuffer, dataOffset + 4, dataSize - 4);
+                        } else if (packetType === 1) {
+                            // One or more Nalus
+                            this._parseAVCVideoData(arrayBuffer, dataOffset + 4, dataSize - 4, tagTimestamp, tagPosition, frameType, cts);
+                        } else if (packetType === 2) {
+                            // empty, AVC end of sequence
+                        } else {
+                            this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid video packet type ' + packetType);
+                            return;
+                        }
+                    }
+                }, {
+                    key: '_parseAVCDecoderConfigurationRecord',
+                    value: function _parseAVCDecoderConfigurationRecord(arrayBuffer, dataOffset, dataSize) {
+                        if (dataSize < 7) {
+                            _logger2.default.w(this.TAG, 'Flv: Invalid AVCDecoderConfigurationRecord, lack of data!');
+                            return;
+                        }
+
+                        var meta = this._videoMetadata;
+                        var track = this._videoTrack;
+                        var le = this._littleEndian;
+                        var v = new DataView(arrayBuffer, dataOffset, dataSize);
+
+                        if (!meta) {
+                            if (this._hasVideo === false && this._hasVideoFlagOverrided === false) {
+                                this._hasVideo = true;
+                                this._mediaInfo.hasVideo = true;
+                            }
+
+                            meta = this._videoMetadata = {};
+                            meta.type = 'video';
+                            meta.id = track.id;
+                            meta.timescale = this._timescale;
+                            meta.duration = this._duration;
+                        } else {
+                            if (typeof meta.avcc !== 'undefined') {
+                                _logger2.default.w(this.TAG, 'Found another AVCDecoderConfigurationRecord!');
+                            }
+                        }
+
+                        var version = v.getUint8(0); // configurationVersion
+                        var avcProfile = v.getUint8(1); // avcProfileIndication
+                        var profileCompatibility = v.getUint8(2); // profile_compatibility
+                        var avcLevel = v.getUint8(3); // AVCLevelIndication
+
+                        if (version !== 1 || avcProfile === 0) {
+                            this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid AVCDecoderConfigurationRecord');
+                            return;
+                        }
+
+                        this._naluLengthSize = (v.getUint8(4) & 3) + 1; // lengthSizeMinusOne
+                        if (this._naluLengthSize !== 3 && this._naluLengthSize !== 4) {
+                            // holy shit!!!
+                            this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Strange NaluLengthSizeMinusOne: ' + (this._naluLengthSize - 1));
+                            return;
+                        }
+
+                        var spsCount = v.getUint8(5) & 31; // numOfSequenceParameterSets
+                        if (spsCount === 0) {
+                            this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid AVCDecoderConfigurationRecord: No SPS');
+                            return;
+                        } else if (spsCount > 1) {
+                            _logger2.default.w(this.TAG, 'Flv: Strange AVCDecoderConfigurationRecord: SPS Count = ' + spsCount);
+                        }
+
+                        var offset = 6;
+
+                        for (var i = 0; i < spsCount; i++) {
+                            var len = v.getUint16(offset, !le); // sequenceParameterSetLength
+                            offset += 2;
+
+                            if (len === 0) {
+                                continue;
+                            }
+
+                            // Notice: Nalu without startcode header (00 00 00 01)
+                            var sps = new Uint8Array(arrayBuffer, dataOffset + offset, len);
+                            offset += len;
+
+                            var config = _spsParser2.default.parseSPS(sps);
+                            if (i !== 0) {
+                                // ignore other sps's config
+                                continue;
+                            }
+
+                            meta.codecWidth = config.codec_size.width;
+                            meta.codecHeight = config.codec_size.height;
+                            meta.presentWidth = config.present_size.width;
+                            meta.presentHeight = config.present_size.height;
+
+                            meta.profile = config.profile_string;
+                            meta.level = config.level_string;
+                            meta.bitDepth = config.bit_depth;
+                            meta.chromaFormat = config.chroma_format;
+                            meta.sarRatio = config.sar_ratio;
+                            meta.frameRate = config.frame_rate;
+
+                            if (config.frame_rate.fixed === false || config.frame_rate.fps_num === 0 || config.frame_rate.fps_den === 0) {
+                                meta.frameRate = this._referenceFrameRate;
+                            }
+
+                            var fps_den = meta.frameRate.fps_den;
+                            var fps_num = meta.frameRate.fps_num;
+                            meta.refSampleDuration = meta.timescale * (fps_den / fps_num);
+
+                            var codecArray = sps.subarray(1, 4);
+                            var codecString = 'avc1.';
+                            for (var j = 0; j < 3; j++) {
+                                var h = codecArray[j].toString(16);
+                                if (h.length < 2) {
+                                    h = '0' + h;
+                                }
+                                codecString += h;
+                            }
+                            meta.codec = codecString;
+
+                            var mi = this._mediaInfo;
+                            mi.width = meta.codecWidth;
+                            mi.height = meta.codecHeight;
+                            mi.fps = meta.frameRate.fps;
+                            mi.profile = meta.profile;
+                            mi.level = meta.level;
+                            mi.refFrames = config.ref_frames;
+                            mi.chromaFormat = config.chroma_format_string;
+                            mi.sarNum = meta.sarRatio.width;
+                            mi.sarDen = meta.sarRatio.height;
+                            mi.videoCodec = codecString;
+
+                            if (mi.hasAudio) {
+                                if (mi.audioCodec != null) {
+                                    mi.mimeType = 'video/x-flv; codecs="' + mi.videoCodec + ',' + mi.audioCodec + '"';
+                                }
+                            } else {
+                                mi.mimeType = 'video/x-flv; codecs="' + mi.videoCodec + '"';
+                            }
+                            if (mi.isComplete()) {
+                                this._onMediaInfo(mi);
+                            }
+                        }
+
+                        var ppsCount = v.getUint8(offset); // numOfPictureParameterSets
+                        if (ppsCount === 0) {
+                            this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid AVCDecoderConfigurationRecord: No PPS');
+                            return;
+                        } else if (ppsCount > 1) {
+                            _logger2.default.w(this.TAG, 'Flv: Strange AVCDecoderConfigurationRecord: PPS Count = ' + ppsCount);
+                        }
+
+                        offset++;
+
+                        for (var _i = 0; _i < ppsCount; _i++) {
+                            var _len = v.getUint16(offset, !le); // pictureParameterSetLength
+                            offset += 2;
+
+                            if (_len === 0) {
+                                continue;
+                            }
+
+                            // pps is useless for extracting video information
+                            offset += _len;
+                        }
+
+                        meta.avcc = new Uint8Array(dataSize);
+                        meta.avcc.set(new Uint8Array(arrayBuffer, dataOffset, dataSize), 0);
+                        _logger2.default.v(this.TAG, 'Parsed AVCDecoderConfigurationRecord');
+
+                        if (this._isInitialMetadataDispatched()) {
+                            // flush parsed frames
+                            if (this._dispatch && (this._audioTrack.length || this._videoTrack.length)) {
+                                this._onDataAvailable(this._audioTrack, this._videoTrack);
+                            }
+                        } else {
+                            this._videoInitialMetadataDispatched = true;
+                        }
+                        // notify new metadata
+                        this._dispatch = false;
+                        this._onTrackMetadata('video', meta);
+                    }
+                }, {
+                    key: '_parseAVCVideoData',
+                    value: function _parseAVCVideoData(arrayBuffer, dataOffset, dataSize, tagTimestamp, tagPosition, frameType, cts) {
+                        var le = this._littleEndian;
+                        var v = new DataView(arrayBuffer, dataOffset, dataSize);
+
+                        var units = [],
+                            length = 0;
+
+                        var offset = 0;
+                        var lengthSize = this._naluLengthSize;
+                        var dts = this._timestampBase + tagTimestamp;
+                        var keyframe = frameType === 1; // from FLV Frame Type constants
+
+                        while (offset < dataSize) {
+                            if (offset + 4 >= dataSize) {
+                                _logger2.default.w(this.TAG, 'Malformed Nalu near timestamp ' + dts + ', offset = ' + offset + ', dataSize = ' + dataSize);
+                                break; // data not enough for next Nalu
+                            }
+                            // Nalu with length-header (AVC1)
+                            var naluSize = v.getUint32(offset, !le); // Big-Endian read
+                            if (lengthSize === 3) {
+                                naluSize >>>= 8;
+                            }
+                            if (naluSize > dataSize - lengthSize) {
+                                _logger2.default.w(this.TAG, 'Malformed Nalus near timestamp ' + dts + ', NaluSize > DataSize!');
+                                return;
+                            }
+
+                            var unitType = v.getUint8(offset + lengthSize) & 0x1F;
+
+                            if (unitType === 5) {
+                                // IDR
+                                keyframe = true;
+                            }
+
+                            var data = new Uint8Array(arrayBuffer, dataOffset + offset, lengthSize + naluSize);
+                            var unit = { type: unitType, data: data };
+                            units.push(unit);
+                            length += data.byteLength;
+
+                            offset += lengthSize + naluSize;
+                        }
+
+                        if (units.length) {
+                            var track = this._videoTrack;
+                            var avcSample = {
+                                units: units,
+                                length: length,
+                                isKeyframe: keyframe,
+                                dts: dts,
+                                cts: cts,
+                                pts: dts + cts
+                            };
+                            if (keyframe) {
+                                avcSample.fileposition = tagPosition;
+                            }
+                            track.samples.push(avcSample);
+                            track.length += length;
+                        }
+                    }
+                }, {
+                    key: 'onTrackMetadata',
+                    get: function get() {
+                        return this._onTrackMetadata;
+                    },
+                    set: function set(callback) {
+                        this._onTrackMetadata = callback;
+                    }
+
+                    // prototype: function(mediaInfo: MediaInfo): void
+
+                }, {
+                    key: 'onMediaInfo',
+                    get: function get() {
+                        return this._onMediaInfo;
+                    },
+                    set: function set(callback) {
+                        this._onMediaInfo = callback;
+                    }
+                }, {
+                    key: 'onMetaDataArrived',
+                    get: function get() {
+                        return this._onMetaDataArrived;
+                    },
+                    set: function set(callback) {
+                        this._onMetaDataArrived = callback;
+                    }
+                }, {
+                    key: 'onScriptDataArrived',
+                    get: function get() {
+                        return this._onScriptDataArrived;
+                    },
+                    set: function set(callback) {
+                        this._onScriptDataArrived = callback;
+                    }
+
+                    // prototype: function(type: number, info: string): void
+
+                }, {
+                    key: 'onError',
+                    get: function get() {
+                        return this._onError;
+                    },
+                    set: function set(callback) {
+                        this._onError = callback;
+                    }
+
+                    // prototype: function(videoTrack: any, audioTrack: any): void
+
+                }, {
+                    key: 'onDataAvailable',
+                    get: function get() {
+                        return this._onDataAvailable;
+                    },
+                    set: function set(callback) {
+                        this._onDataAvailable = callback;
+                    }
+
+                    // timestamp base for output samples, must be in milliseconds
+
+                }, {
+                    key: 'timestampBase',
+                    get: function get() {
+                        return this._timestampBase;
+                    },
+                    set: function set(base) {
+                        this._timestampBase = base;
+                    }
+                }, {
+                    key: 'overridedDuration',
+                    get: function get() {
+                        return this._duration;
+                    }
+
+                    // Force-override media duration. Must be in milliseconds, int32
+                    ,
+                    set: function set(duration) {
+                        this._durationOverrided = true;
                         this._duration = duration;
                         this._mediaInfo.duration = duration;
                     }
-                } else {
-                    this._mediaInfo.duration = 0;
-                }
-                if (typeof onMetaData.framerate === 'number') {
-                    // framerate
-                    var fps_num = Math.floor(onMetaData.framerate * 1000);
-                    if (fps_num > 0) {
-                        var fps = fps_num / 1000;
-                        this._referenceFrameRate.fixed = true;
-                        this._referenceFrameRate.fps = fps;
-                        this._referenceFrameRate.fps_num = fps_num;
-                        this._referenceFrameRate.fps_den = 1000;
-                        this._mediaInfo.fps = fps;
+
+                    // Force-override audio track present flag, boolean
+
+                }, {
+                    key: 'overridedHasAudio',
+                    set: function set(hasAudio) {
+                        this._hasAudioFlagOverrided = true;
+                        this._hasAudio = hasAudio;
+                        this._mediaInfo.hasAudio = hasAudio;
                     }
-                }
-                if (_typeof(onMetaData.keyframes) === 'object') {
-                    // keyframes
-                    this._mediaInfo.hasKeyframesIndex = true;
-                    var keyframes = onMetaData.keyframes;
-                    this._mediaInfo.keyframesIndex = this._parseKeyframesIndex(keyframes);
-                    onMetaData.keyframes = null; // keyframes has been extracted, remove it
-                } else {
-                    this._mediaInfo.hasKeyframesIndex = false;
-                }
-                this._dispatch = false;
-                this._mediaInfo.metadata = onMetaData;
-                _logger2.default.v(this.TAG, 'Parsed onMetaData');
-                if (this._mediaInfo.isComplete()) {
-                    this._onMediaInfo(this._mediaInfo);
-                }
-            }
 
-            if (Object.keys(scriptData).length > 0) {
-                if (this._onScriptDataArrived) {
-                    this._onScriptDataArrived(Object.assign({}, scriptData));
-                }
-            }
-        }
-    }, {
-        key: '_parseKeyframesIndex',
-        value: function _parseKeyframesIndex(keyframes) {
-            var times = [];
-            var filepositions = [];
+                    // Force-override video track present flag, boolean
 
-            // ignore first keyframe which is actually AVC Sequence Header (AVCDecoderConfigurationRecord)
-            for (var i = 1; i < keyframes.times.length; i++) {
-                var time = this._timestampBase + Math.floor(keyframes.times[i] * 1000);
-                times.push(time);
-                filepositions.push(keyframes.filepositions[i]);
-            }
-
-            return {
-                times: times,
-                filepositions: filepositions
-            };
-        }
-    }, {
-        key: '_parseAudioData',
-        value: function _parseAudioData(arrayBuffer, dataOffset, dataSize, tagTimestamp) {
-            if (dataSize <= 1) {
-                _logger2.default.w(this.TAG, 'Flv: Invalid audio packet, missing SoundData payload!');
-                return;
-            }
-
-            if (this._hasAudioFlagOverrided === true && this._hasAudio === false) {
-                // If hasAudio: false indicated explicitly in MediaDataSource,
-                // Ignore all the audio packets
-                return;
-            }
-
-            var le = this._littleEndian;
-            var v = new DataView(arrayBuffer, dataOffset, dataSize);
-
-            var soundSpec = v.getUint8(0);
-
-            var soundFormat = soundSpec >>> 4;
-            if (soundFormat !== 2 && soundFormat !== 10) {
-                // MP3 or AAC
-                this._onError(_demuxErrors2.default.CODEC_UNSUPPORTED, 'Flv: Unsupported audio codec idx: ' + soundFormat);
-                return;
-            }
-
-            var soundRate = 0;
-            var soundRateIndex = (soundSpec & 12) >>> 2;
-            if (soundRateIndex >= 0 && soundRateIndex <= 4) {
-                soundRate = this._flvSoundRateTable[soundRateIndex];
-            } else {
-                this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid audio sample rate idx: ' + soundRateIndex);
-                return;
-            }
-
-            var soundSize = (soundSpec & 2) >>> 1; // unused
-            var soundType = soundSpec & 1;
-
-            var meta = this._audioMetadata;
-            var track = this._audioTrack;
-
-            if (!meta) {
-                if (this._hasAudio === false && this._hasAudioFlagOverrided === false) {
-                    this._hasAudio = true;
-                    this._mediaInfo.hasAudio = true;
-                }
-
-                // initial metadata
-                meta = this._audioMetadata = {};
-                meta.type = 'audio';
-                meta.id = track.id;
-                meta.timescale = this._timescale;
-                meta.duration = this._duration;
-                meta.audioSampleRate = soundRate;
-                meta.channelCount = soundType === 0 ? 1 : 2;
-            }
-
-            if (soundFormat === 10) {
-                // AAC
-                var aacData = this._parseAACAudioData(arrayBuffer, dataOffset + 1, dataSize - 1);
-                if (aacData == undefined) {
-                    return;
-                }
-
-                if (aacData.packetType === 0) {
-                    // AAC sequence header (AudioSpecificConfig)
-                    if (meta.config) {
-                        _logger2.default.w(this.TAG, 'Found another AudioSpecificConfig!');
+                }, {
+                    key: 'overridedHasVideo',
+                    set: function set(hasVideo) {
+                        this._hasVideoFlagOverrided = true;
+                        this._hasVideo = hasVideo;
+                        this._mediaInfo.hasVideo = hasVideo;
                     }
-                    var misc = aacData.data;
-                    meta.audioSampleRate = misc.samplingRate;
-                    meta.channelCount = misc.channelCount;
-                    meta.codec = misc.codec;
-                    meta.originalCodec = misc.originalCodec;
-                    meta.config = misc.config;
-                    // The decode result of an aac sample is 1024 PCM samples
-                    meta.refSampleDuration = 1024 / meta.audioSampleRate * meta.timescale;
-                    _logger2.default.v(this.TAG, 'Parsed AudioSpecificConfig');
+                }], [{
+                    key: 'probe',
+                    value: function probe(buffer) {
+                        var data = new Uint8Array(buffer);
+                        var mismatch = { match: false };
 
-                    if (this._isInitialMetadataDispatched()) {
-                        // Non-initial metadata, force dispatch (or flush) parsed frames to remuxer
-                        if (this._dispatch && (this._audioTrack.length || this._videoTrack.length)) {
-                            this._onDataAvailable(this._audioTrack, this._videoTrack);
+                        if (data[0] !== 0x46 || data[1] !== 0x4C || data[2] !== 0x56 || data[3] !== 0x01) {
+                            return mismatch;
                         }
-                    } else {
-                        this._audioInitialMetadataDispatched = true;
-                    }
-                    // then notify new metadata
-                    this._dispatch = false;
-                    this._onTrackMetadata('audio', meta);
 
-                    var mi = this._mediaInfo;
-                    mi.audioCodec = meta.originalCodec;
-                    mi.audioSampleRate = meta.audioSampleRate;
-                    mi.audioChannelCount = meta.channelCount;
-                    if (mi.hasVideo) {
-                        if (mi.videoCodec != null) {
-                            mi.mimeType = 'video/x-flv; codecs="' + mi.videoCodec + ',' + mi.audioCodec + '"';
+                        var hasAudio = (data[4] & 4) >>> 2 !== 0;
+                        var hasVideo = (data[4] & 1) !== 0;
+
+                        var offset = ReadBig32(data, 5);
+
+                        if (offset < 9) {
+                            return mismatch;
                         }
-                    } else {
-                        mi.mimeType = 'video/x-flv; codecs="' + mi.audioCodec + '"';
+
+                        return {
+                            match: true,
+                            consumed: offset,
+                            dataOffset: offset,
+                            hasAudioTrack: hasAudio,
+                            hasVideoTrack: hasVideo
+                        };
                     }
-                    if (mi.isComplete()) {
-                        this._onMediaInfo(mi);
-                    }
-                } else if (aacData.packetType === 1) {
-                    // AAC raw frame data
-                    var dts = this._timestampBase + tagTimestamp;
-                    var aacSample = { unit: aacData.data, length: aacData.data.byteLength, dts: dts, pts: dts };
-                    track.samples.push(aacSample);
-                    track.length += aacData.data.length;
-                } else {
-                    _logger2.default.e(this.TAG, 'Flv: Unsupported AAC data type ' + aacData.packetType);
-                }
-            } else if (soundFormat === 2) {
-                // MP3
-                if (!meta.codec) {
-                    // We need metadata for mp3 audio track, extract info from frame header
-                    var _misc = this._parseMP3AudioData(arrayBuffer, dataOffset + 1, dataSize - 1, true);
-                    if (_misc == undefined) {
-                        return;
-                    }
-                    meta.audioSampleRate = _misc.samplingRate;
-                    meta.channelCount = _misc.channelCount;
-                    meta.codec = _misc.codec;
-                    meta.originalCodec = _misc.originalCodec;
-                    // The decode result of an mp3 sample is 1152 PCM samples
-                    meta.refSampleDuration = 1152 / meta.audioSampleRate * meta.timescale;
-                    _logger2.default.v(this.TAG, 'Parsed MPEG Audio Frame Header');
+                }]);
 
-                    this._audioInitialMetadataDispatched = true;
-                    this._onTrackMetadata('audio', meta);
+                return FLVDemuxer;
+            }();
 
-                    var _mi = this._mediaInfo;
-                    _mi.audioCodec = meta.codec;
-                    _mi.audioSampleRate = meta.audioSampleRate;
-                    _mi.audioChannelCount = meta.channelCount;
-                    _mi.audioDataRate = _misc.bitRate;
-                    if (_mi.hasVideo) {
-                        if (_mi.videoCodec != null) {
-                            _mi.mimeType = 'video/x-flv; codecs="' + _mi.videoCodec + ',' + _mi.audioCodec + '"';
-                        }
-                    } else {
-                        _mi.mimeType = 'video/x-flv; codecs="' + _mi.audioCodec + '"';
-                    }
-                    if (_mi.isComplete()) {
-                        this._onMediaInfo(_mi);
-                    }
-                }
+            exports.default = FLVDemuxer;
 
-                // This packet is always a valid audio packet, extract it
-                var data = this._parseMP3AudioData(arrayBuffer, dataOffset + 1, dataSize - 1, false);
-                if (data == undefined) {
-                    return;
-                }
-                var _dts = this._timestampBase + tagTimestamp;
-                var mp3Sample = { unit: data, length: data.byteLength, dts: _dts, pts: _dts };
-                track.samples.push(mp3Sample);
-                track.length += data.length;
-            }
-        }
-    }, {
-        key: '_parseAACAudioData',
-        value: function _parseAACAudioData(arrayBuffer, dataOffset, dataSize) {
-            if (dataSize <= 1) {
-                _logger2.default.w(this.TAG, 'Flv: Invalid AAC packet, missing AACPacketType or/and Data!');
-                return;
-            }
+        }, { "../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) {
+            'use strict';
 
-            var result = {};
-            var array = new Uint8Array(arrayBuffer, dataOffset, dataSize);
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
 
-            result.packetType = array[0];
-
-            if (array[0] === 0) {
-                result.data = this._parseAACAudioSpecificConfig(arrayBuffer, dataOffset + 1, dataSize - 1);
-            } else {
-                result.data = array.subarray(1);
-            }
-
-            return result;
-        }
-    }, {
-        key: '_parseAACAudioSpecificConfig',
-        value: function _parseAACAudioSpecificConfig(arrayBuffer, dataOffset, dataSize) {
-            var array = new Uint8Array(arrayBuffer, dataOffset, dataSize);
-            var config = null;
-
-            /* Audio Object Type:
-               0: Null
-               1: AAC Main
-               2: AAC LC
-               3: AAC SSR (Scalable Sample Rate)
-               4: AAC LTP (Long Term Prediction)
-               5: HE-AAC / SBR (Spectral Band Replication)
-               6: AAC Scalable
-            */
-
-            var audioObjectType = 0;
-            var originalAudioObjectType = 0;
-            var audioExtensionObjectType = null;
-            var samplingIndex = 0;
-            var extensionSamplingIndex = null;
-
-            // 5 bits
-            audioObjectType = originalAudioObjectType = array[0] >>> 3;
-            // 4 bits
-            samplingIndex = (array[0] & 0x07) << 1 | array[1] >>> 7;
-            if (samplingIndex < 0 || samplingIndex >= this._mpegSamplingRates.length) {
-                this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: AAC invalid sampling frequency index!');
-                return;
-            }
-
-            var samplingFrequence = this._mpegSamplingRates[samplingIndex];
-
-            // 4 bits
-            var channelConfig = (array[1] & 0x78) >>> 3;
-            if (channelConfig < 0 || channelConfig >= 8) {
-                this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: AAC invalid channel configuration');
-                return;
-            }
-
-            if (audioObjectType === 5) {
-                // HE-AAC?
-                // 4 bits
-                extensionSamplingIndex = (array[1] & 0x07) << 1 | array[2] >>> 7;
-                // 5 bits
-                audioExtensionObjectType = (array[2] & 0x7C) >>> 2;
-            }
-
-            // workarounds for various browsers
-            var userAgent = self.navigator.userAgent.toLowerCase();
-
-            if (userAgent.indexOf('firefox') !== -1) {
-                // firefox: use SBR (HE-AAC) if freq less than 24kHz
-                if (samplingIndex >= 6) {
-                    audioObjectType = 5;
-                    config = new Array(4);
-                    extensionSamplingIndex = samplingIndex - 3;
-                } else {
-                    // use LC-AAC
-                    audioObjectType = 2;
-                    config = new Array(2);
-                    extensionSamplingIndex = samplingIndex;
-                }
-            } else if (userAgent.indexOf('android') !== -1) {
-                // android: always use LC-AAC
-                audioObjectType = 2;
-                config = new Array(2);
-                extensionSamplingIndex = samplingIndex;
-            } else {
-                // for other browsers, e.g. chrome...
-                // Always use HE-AAC to make it easier to switch aac codec profile
-                audioObjectType = 5;
-                extensionSamplingIndex = samplingIndex;
-                config = new Array(4);
-
-                if (samplingIndex >= 6) {
-                    extensionSamplingIndex = samplingIndex - 3;
-                } else if (channelConfig === 1) {
-                    // Mono channel
-                    audioObjectType = 2;
-                    config = new Array(2);
-                    extensionSamplingIndex = samplingIndex;
-                }
-            }
-
-            config[0] = audioObjectType << 3;
-            config[0] |= (samplingIndex & 0x0F) >>> 1;
-            config[1] = (samplingIndex & 0x0F) << 7;
-            config[1] |= (channelConfig & 0x0F) << 3;
-            if (audioObjectType === 5) {
-                config[1] |= (extensionSamplingIndex & 0x0F) >>> 1;
-                config[2] = (extensionSamplingIndex & 0x01) << 7;
-                // extended audio object type: force to 2 (LC-AAC)
-                config[2] |= 2 << 2;
-                config[3] = 0;
-            }
-
-            return {
-                config: config,
-                samplingRate: samplingFrequence,
-                channelCount: channelConfig,
-                codec: 'mp4a.40.' + audioObjectType,
-                originalCodec: 'mp4a.40.' + originalAudioObjectType
-            };
-        }
-    }, {
-        key: '_parseMP3AudioData',
-        value: function _parseMP3AudioData(arrayBuffer, dataOffset, dataSize, requestHeader) {
-            if (dataSize < 4) {
-                _logger2.default.w(this.TAG, 'Flv: Invalid MP3 packet, header missing!');
-                return;
-            }
-
-            var le = this._littleEndian;
-            var array = new Uint8Array(arrayBuffer, dataOffset, dataSize);
-            var result = null;
-
-            if (requestHeader) {
-                if (array[0] !== 0xFF) {
-                    return;
-                }
-                var ver = array[1] >>> 3 & 0x03;
-                var layer = (array[1] & 0x06) >> 1;
-
-                var bitrate_index = (array[2] & 0xF0) >>> 4;
-                var sampling_freq_index = (array[2] & 0x0C) >>> 2;
-
-                var channel_mode = array[3] >>> 6 & 0x03;
-                var channel_count = channel_mode !== 3 ? 2 : 1;
-
-                var sample_rate = 0;
-                var bit_rate = 0;
-                var object_type = 34; // Layer-3, listed in MPEG-4 Audio Object Types
-
-                var codec = 'mp3';
-
-                switch (ver) {
-                    case 0:
-                        // MPEG 2.5
-                        sample_rate = this._mpegAudioV25SampleRateTable[sampling_freq_index];
-                        break;
-                    case 2:
-                        // MPEG 2
-                        sample_rate = this._mpegAudioV20SampleRateTable[sampling_freq_index];
-                        break;
-                    case 3:
-                        // MPEG 1
-                        sample_rate = this._mpegAudioV10SampleRateTable[sampling_freq_index];
-                        break;
-                }
-
-                switch (layer) {
-                    case 1:
-                        // Layer 3
-                        object_type = 34;
-                        if (bitrate_index < this._mpegAudioL3BitRateTable.length) {
-                            bit_rate = this._mpegAudioL3BitRateTable[bitrate_index];
-                        }
-                        break;
-                    case 2:
-                        // Layer 2
-                        object_type = 33;
-                        if (bitrate_index < this._mpegAudioL2BitRateTable.length) {
-                            bit_rate = this._mpegAudioL2BitRateTable[bitrate_index];
-                        }
-                        break;
-                    case 3:
-                        // Layer 1
-                        object_type = 32;
-                        if (bitrate_index < this._mpegAudioL1BitRateTable.length) {
-                            bit_rate = this._mpegAudioL1BitRateTable[bitrate_index];
-                        }
-                        break;
-                }
-
-                result = {
-                    bitRate: bit_rate,
-                    samplingRate: sample_rate,
-                    channelCount: channel_count,
-                    codec: codec,
-                    originalCodec: codec
-                };
-            } else {
-                result = array;
-            }
-
-            return result;
-        }
-    }, {
-        key: '_parseVideoData',
-        value: function _parseVideoData(arrayBuffer, dataOffset, dataSize, tagTimestamp, tagPosition) {
-            if (dataSize <= 1) {
-                _logger2.default.w(this.TAG, 'Flv: Invalid video packet, missing VideoData payload!');
-                return;
-            }
-
-            if (this._hasVideoFlagOverrided === true && this._hasVideo === false) {
-                // If hasVideo: false indicated explicitly in MediaDataSource,
-                // Ignore all the video packets
-                return;
-            }
-
-            var spec = new Uint8Array(arrayBuffer, dataOffset, dataSize)[0];
-
-            var frameType = (spec & 240) >>> 4;
-            var codecId = spec & 15;
-
-            if (codecId !== 7) {
-                this._onError(_demuxErrors2.default.CODEC_UNSUPPORTED, 'Flv: Unsupported codec in video frame: ' + codecId);
-                return;
-            }
-
-            this._parseAVCVideoPacket(arrayBuffer, dataOffset + 1, dataSize - 1, tagTimestamp, tagPosition, frameType);
-        }
-    }, {
-        key: '_parseAVCVideoPacket',
-        value: function _parseAVCVideoPacket(arrayBuffer, dataOffset, dataSize, tagTimestamp, tagPosition, frameType) {
-            if (dataSize < 4) {
-                _logger2.default.w(this.TAG, 'Flv: Invalid AVC packet, missing AVCPacketType or/and CompositionTime');
-                return;
-            }
-
-            var le = this._littleEndian;
-            var v = new DataView(arrayBuffer, dataOffset, dataSize);
-
-            var packetType = v.getUint8(0);
-            var cts_unsigned = v.getUint32(0, !le) & 0x00FFFFFF;
-            var cts = cts_unsigned << 8 >> 8; // convert to 24-bit signed int
-
-            if (packetType === 0) {
-                // AVCDecoderConfigurationRecord
-                this._parseAVCDecoderConfigurationRecord(arrayBuffer, dataOffset + 4, dataSize - 4);
-            } else if (packetType === 1) {
-                // One or more Nalus
-                this._parseAVCVideoData(arrayBuffer, dataOffset + 4, dataSize - 4, tagTimestamp, tagPosition, frameType, cts);
-            } else if (packetType === 2) {
-                // empty, AVC end of sequence
-            } else {
-                this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid video packet type ' + packetType);
-                return;
-            }
-        }
-    }, {
-        key: '_parseAVCDecoderConfigurationRecord',
-        value: function _parseAVCDecoderConfigurationRecord(arrayBuffer, dataOffset, dataSize) {
-            if (dataSize < 7) {
-                _logger2.default.w(this.TAG, 'Flv: Invalid AVCDecoderConfigurationRecord, lack of data!');
-                return;
-            }
-
-            var meta = this._videoMetadata;
-            var track = this._videoTrack;
-            var le = this._littleEndian;
-            var v = new DataView(arrayBuffer, dataOffset, dataSize);
-
-            if (!meta) {
-                if (this._hasVideo === false && this._hasVideoFlagOverrided === false) {
-                    this._hasVideo = true;
-                    this._mediaInfo.hasVideo = true;
-                }
-
-                meta = this._videoMetadata = {};
-                meta.type = 'video';
-                meta.id = track.id;
-                meta.timescale = this._timescale;
-                meta.duration = this._duration;
-            } else {
-                if (typeof meta.avcc !== 'undefined') {
-                    _logger2.default.w(this.TAG, 'Found another AVCDecoderConfigurationRecord!');
-                }
-            }
-
-            var version = v.getUint8(0); // configurationVersion
-            var avcProfile = v.getUint8(1); // avcProfileIndication
-            var profileCompatibility = v.getUint8(2); // profile_compatibility
-            var avcLevel = v.getUint8(3); // AVCLevelIndication
-
-            if (version !== 1 || avcProfile === 0) {
-                this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid AVCDecoderConfigurationRecord');
-                return;
-            }
-
-            this._naluLengthSize = (v.getUint8(4) & 3) + 1; // lengthSizeMinusOne
-            if (this._naluLengthSize !== 3 && this._naluLengthSize !== 4) {
-                // holy shit!!!
-                this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Strange NaluLengthSizeMinusOne: ' + (this._naluLengthSize - 1));
-                return;
-            }
-
-            var spsCount = v.getUint8(5) & 31; // numOfSequenceParameterSets
-            if (spsCount === 0) {
-                this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid AVCDecoderConfigurationRecord: No SPS');
-                return;
-            } else if (spsCount > 1) {
-                _logger2.default.w(this.TAG, 'Flv: Strange AVCDecoderConfigurationRecord: SPS Count = ' + spsCount);
-            }
-
-            var offset = 6;
-
-            for (var i = 0; i < spsCount; i++) {
-                var len = v.getUint16(offset, !le); // sequenceParameterSetLength
-                offset += 2;
-
-                if (len === 0) {
-                    continue;
-                }
-
-                // Notice: Nalu without startcode header (00 00 00 01)
-                var sps = new Uint8Array(arrayBuffer, dataOffset + offset, len);
-                offset += len;
-
-                var config = _spsParser2.default.parseSPS(sps);
-                if (i !== 0) {
-                    // ignore other sps's config
-                    continue;
-                }
-
-                meta.codecWidth = config.codec_size.width;
-                meta.codecHeight = config.codec_size.height;
-                meta.presentWidth = config.present_size.width;
-                meta.presentHeight = config.present_size.height;
-
-                meta.profile = config.profile_string;
-                meta.level = config.level_string;
-                meta.bitDepth = config.bit_depth;
-                meta.chromaFormat = config.chroma_format;
-                meta.sarRatio = config.sar_ratio;
-                meta.frameRate = config.frame_rate;
-
-                if (config.frame_rate.fixed === false || config.frame_rate.fps_num === 0 || config.frame_rate.fps_den === 0) {
-                    meta.frameRate = this._referenceFrameRate;
-                }
-
-                var fps_den = meta.frameRate.fps_den;
-                var fps_num = meta.frameRate.fps_num;
-                meta.refSampleDuration = meta.timescale * (fps_den / fps_num);
-
-                var codecArray = sps.subarray(1, 4);
-                var codecString = 'avc1.';
-                for (var j = 0; j < 3; j++) {
-                    var h = codecArray[j].toString(16);
-                    if (h.length < 2) {
-                        h = '0' + h;
-                    }
-                    codecString += h;
-                }
-                meta.codec = codecString;
-
-                var mi = this._mediaInfo;
-                mi.width = meta.codecWidth;
-                mi.height = meta.codecHeight;
-                mi.fps = meta.frameRate.fps;
-                mi.profile = meta.profile;
-                mi.level = meta.level;
-                mi.refFrames = config.ref_frames;
-                mi.chromaFormat = config.chroma_format_string;
-                mi.sarNum = meta.sarRatio.width;
-                mi.sarDen = meta.sarRatio.height;
-                mi.videoCodec = codecString;
-
-                if (mi.hasAudio) {
-                    if (mi.audioCodec != null) {
-                        mi.mimeType = 'video/x-flv; codecs="' + mi.videoCodec + ',' + mi.audioCodec + '"';
-                    }
-                } else {
-                    mi.mimeType = 'video/x-flv; codecs="' + mi.videoCodec + '"';
-                }
-                if (mi.isComplete()) {
-                    this._onMediaInfo(mi);
-                }
-            }
-
-            var ppsCount = v.getUint8(offset); // numOfPictureParameterSets
-            if (ppsCount === 0) {
-                this._onError(_demuxErrors2.default.FORMAT_ERROR, 'Flv: Invalid AVCDecoderConfigurationRecord: No PPS');
-                return;
-            } else if (ppsCount > 1) {
-                _logger2.default.w(this.TAG, 'Flv: Strange AVCDecoderConfigurationRecord: PPS Count = ' + ppsCount);
-            }
-
-            offset++;
-
-            for (var _i = 0; _i < ppsCount; _i++) {
-                var _len = v.getUint16(offset, !le); // pictureParameterSetLength
-                offset += 2;
-
-                if (_len === 0) {
-                    continue;
-                }
-
-                // pps is useless for extracting video information
-                offset += _len;
-            }
-
-            meta.avcc = new Uint8Array(dataSize);
-            meta.avcc.set(new Uint8Array(arrayBuffer, dataOffset, dataSize), 0);
-            _logger2.default.v(this.TAG, 'Parsed AVCDecoderConfigurationRecord');
-
-            if (this._isInitialMetadataDispatched()) {
-                // flush parsed frames
-                if (this._dispatch && (this._audioTrack.length || this._videoTrack.length)) {
-                    this._onDataAvailable(this._audioTrack, this._videoTrack);
-                }
-            } else {
-                this._videoInitialMetadataDispatched = true;
-            }
-            // notify new metadata
-            this._dispatch = false;
-            this._onTrackMetadata('video', meta);
-        }
-    }, {
-        key: '_parseAVCVideoData',
-        value: function _parseAVCVideoData(arrayBuffer, dataOffset, dataSize, tagTimestamp, tagPosition, frameType, cts) {
-            var le = this._littleEndian;
-            var v = new DataView(arrayBuffer, dataOffset, dataSize);
-
-            var units = [],
-                length = 0;
-
-            var offset = 0;
-            var lengthSize = this._naluLengthSize;
-            var dts = this._timestampBase + tagTimestamp;
-            var keyframe = frameType === 1; // from FLV Frame Type constants
-
-            while (offset < dataSize) {
-                if (offset + 4 >= dataSize) {
-                    _logger2.default.w(this.TAG, 'Malformed Nalu near timestamp ' + dts + ', offset = ' + offset + ', dataSize = ' + dataSize);
-                    break; // data not enough for next Nalu
-                }
-                // Nalu with length-header (AVC1)
-                var naluSize = v.getUint32(offset, !le); // Big-Endian read
-                if (lengthSize === 3) {
-                    naluSize >>>= 8;
-                }
-                if (naluSize > dataSize - lengthSize) {
-                    _logger2.default.w(this.TAG, 'Malformed Nalus near timestamp ' + dts + ', NaluSize > DataSize!');
-                    return;
-                }
-
-                var unitType = v.getUint8(offset + lengthSize) & 0x1F;
-
-                if (unitType === 5) {
-                    // IDR
-                    keyframe = true;
-                }
-
-                var data = new Uint8Array(arrayBuffer, dataOffset + offset, lengthSize + naluSize);
-                var unit = { type: unitType, data: data };
-                units.push(unit);
-                length += data.byteLength;
-
-                offset += lengthSize + naluSize;
-            }
-
-            if (units.length) {
-                var track = this._videoTrack;
-                var avcSample = {
-                    units: units,
-                    length: length,
-                    isKeyframe: keyframe,
-                    dts: dts,
-                    cts: cts,
-                    pts: dts + cts
-                };
-                if (keyframe) {
-                    avcSample.fileposition = tagPosition;
-                }
-                track.samples.push(avcSample);
-                track.length += length;
-            }
-        }
-    }, {
-        key: 'onTrackMetadata',
-        get: function get() {
-            return this._onTrackMetadata;
-        },
-        set: function set(callback) {
-            this._onTrackMetadata = callback;
-        }
-
-        // prototype: function(mediaInfo: MediaInfo): void
-
-    }, {
-        key: 'onMediaInfo',
-        get: function get() {
-            return this._onMediaInfo;
-        },
-        set: function set(callback) {
-            this._onMediaInfo = callback;
-        }
-    }, {
-        key: 'onMetaDataArrived',
-        get: function get() {
-            return this._onMetaDataArrived;
-        },
-        set: function set(callback) {
-            this._onMetaDataArrived = callback;
-        }
-    }, {
-        key: 'onScriptDataArrived',
-        get: function get() {
-            return this._onScriptDataArrived;
-        },
-        set: function set(callback) {
-            this._onScriptDataArrived = callback;
-        }
-
-        // prototype: function(type: number, info: string): void
-
-    }, {
-        key: 'onError',
-        get: function get() {
-            return this._onError;
-        },
-        set: function set(callback) {
-            this._onError = callback;
-        }
-
-        // prototype: function(videoTrack: any, audioTrack: any): void
-
-    }, {
-        key: 'onDataAvailable',
-        get: function get() {
-            return this._onDataAvailable;
-        },
-        set: function set(callback) {
-            this._onDataAvailable = callback;
-        }
-
-        // timestamp base for output samples, must be in milliseconds
-
-    }, {
-        key: 'timestampBase',
-        get: function get() {
-            return this._timestampBase;
-        },
-        set: function set(base) {
-            this._timestampBase = base;
-        }
-    }, {
-        key: 'overridedDuration',
-        get: function get() {
-            return this._duration;
-        }
-
-        // Force-override media duration. Must be in milliseconds, int32
-        ,
-        set: function set(duration) {
-            this._durationOverrided = true;
-            this._duration = duration;
-            this._mediaInfo.duration = duration;
-        }
-
-        // Force-override audio track present flag, boolean
-
-    }, {
-        key: 'overridedHasAudio',
-        set: function set(hasAudio) {
-            this._hasAudioFlagOverrided = true;
-            this._hasAudio = hasAudio;
-            this._mediaInfo.hasAudio = hasAudio;
-        }
-
-        // Force-override video track present flag, boolean
-
-    }, {
-        key: 'overridedHasVideo',
-        set: function set(hasVideo) {
-            this._hasVideoFlagOverrided = true;
-            this._hasVideo = hasVideo;
-            this._mediaInfo.hasVideo = hasVideo;
-        }
-    }], [{
-        key: 'probe',
-        value: function probe(buffer) {
-            var data = new Uint8Array(buffer);
-            var mismatch = { match: false };
-
-            if (data[0] !== 0x46 || data[1] !== 0x4C || data[2] !== 0x56 || data[3] !== 0x01) {
-                return mismatch;
-            }
-
-            var hasAudio = (data[4] & 4) >>> 2 !== 0;
-            var hasVideo = (data[4] & 1) !== 0;
-
-            var offset = ReadBig32(data, 5);
-
-            if (offset < 9) {
-                return mismatch;
-            }
-
-            return {
-                match: true,
-                consumed: offset,
-                dataOffset: offset,
-                hasAudioTrack: hasAudio,
-                hasVideoTrack: hasVideo
-            };
-        }
-    }]);
-
-    return FLVDemuxer;
-}();
-
-exports.default = FLVDemuxer;
-
-},{"../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){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
+            var _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; }; }(); /*
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * Copyright (C) 2016 Bilibili. All Rights Reserved.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       *
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * @author zheng qian <xqq@xqq.im>
@@ -5739,307 +5750,307 @@
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * limitations under the License.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       */
 
-var _expGolomb = _dereq_('./exp-golomb.js');
+            var _expGolomb = _dereq_('./exp-golomb.js');
 
-var _expGolomb2 = _interopRequireDefault(_expGolomb);
+            var _expGolomb2 = _interopRequireDefault(_expGolomb);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var SPSParser = function () {
-    function SPSParser() {
-        _classCallCheck(this, SPSParser);
-    }
+            var SPSParser = function () {
+                function SPSParser() {
+                    _classCallCheck(this, SPSParser);
+                }
 
-    _createClass(SPSParser, null, [{
-        key: '_ebsp2rbsp',
-        value: function _ebsp2rbsp(uint8array) {
-            var src = uint8array;
-            var src_length = src.byteLength;
-            var dst = new Uint8Array(src_length);
-            var dst_idx = 0;
+                _createClass(SPSParser, null, [{
+                    key: '_ebsp2rbsp',
+                    value: function _ebsp2rbsp(uint8array) {
+                        var src = uint8array;
+                        var src_length = src.byteLength;
+                        var dst = new Uint8Array(src_length);
+                        var dst_idx = 0;
 
-            for (var i = 0; i < src_length; i++) {
-                if (i >= 2) {
-                    // Unescape: Skip 0x03 after 00 00
-                    if (src[i] === 0x03 && src[i - 1] === 0x00 && src[i - 2] === 0x00) {
-                        continue;
+                        for (var i = 0; i < src_length; i++) {
+                            if (i >= 2) {
+                                // Unescape: Skip 0x03 after 00 00
+                                if (src[i] === 0x03 && src[i - 1] === 0x00 && src[i - 2] === 0x00) {
+                                    continue;
+                                }
+                            }
+                            dst[dst_idx] = src[i];
+                            dst_idx++;
+                        }
+
+                        return new Uint8Array(dst.buffer, 0, dst_idx);
                     }
-                }
-                dst[dst_idx] = src[i];
-                dst_idx++;
-            }
+                }, {
+                    key: 'parseSPS',
+                    value: function parseSPS(uint8array) {
+                        var rbsp = SPSParser._ebsp2rbsp(uint8array);
+                        var gb = new _expGolomb2.default(rbsp);
 
-            return new Uint8Array(dst.buffer, 0, dst_idx);
-        }
-    }, {
-        key: 'parseSPS',
-        value: function parseSPS(uint8array) {
-            var rbsp = SPSParser._ebsp2rbsp(uint8array);
-            var gb = new _expGolomb2.default(rbsp);
+                        gb.readByte();
+                        var profile_idc = gb.readByte(); // profile_idc
+                        gb.readByte(); // constraint_set_flags[5] + reserved_zero[3]
+                        var level_idc = gb.readByte(); // level_idc
+                        gb.readUEG(); // seq_parameter_set_id
 
-            gb.readByte();
-            var profile_idc = gb.readByte(); // profile_idc
-            gb.readByte(); // constraint_set_flags[5] + reserved_zero[3]
-            var level_idc = gb.readByte(); // level_idc
-            gb.readUEG(); // seq_parameter_set_id
+                        var profile_string = SPSParser.getProfileString(profile_idc);
+                        var level_string = SPSParser.getLevelString(level_idc);
+                        var chroma_format_idc = 1;
+                        var chroma_format = 420;
+                        var chroma_format_table = [0, 420, 422, 444];
+                        var bit_depth = 8;
 
-            var profile_string = SPSParser.getProfileString(profile_idc);
-            var level_string = SPSParser.getLevelString(level_idc);
-            var chroma_format_idc = 1;
-            var chroma_format = 420;
-            var chroma_format_table = [0, 420, 422, 444];
-            var bit_depth = 8;
+                        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) {
 
-            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) {
+                            chroma_format_idc = gb.readUEG();
+                            if (chroma_format_idc === 3) {
+                                gb.readBits(1); // separate_colour_plane_flag
+                            }
+                            if (chroma_format_idc <= 3) {
+                                chroma_format = chroma_format_table[chroma_format_idc];
+                            }
 
-                chroma_format_idc = gb.readUEG();
-                if (chroma_format_idc === 3) {
-                    gb.readBits(1); // separate_colour_plane_flag
-                }
-                if (chroma_format_idc <= 3) {
-                    chroma_format = chroma_format_table[chroma_format_idc];
-                }
-
-                bit_depth = gb.readUEG() + 8; // bit_depth_luma_minus8
-                gb.readUEG(); // bit_depth_chroma_minus8
-                gb.readBits(1); // qpprime_y_zero_transform_bypass_flag
-                if (gb.readBool()) {
-                    // seq_scaling_matrix_present_flag
-                    var scaling_list_count = chroma_format_idc !== 3 ? 8 : 12;
-                    for (var i = 0; i < scaling_list_count; i++) {
-                        if (gb.readBool()) {
-                            // seq_scaling_list_present_flag
-                            if (i < 6) {
-                                SPSParser._skipScalingList(gb, 16);
-                            } else {
-                                SPSParser._skipScalingList(gb, 64);
+                            bit_depth = gb.readUEG() + 8; // bit_depth_luma_minus8
+                            gb.readUEG(); // bit_depth_chroma_minus8
+                            gb.readBits(1); // qpprime_y_zero_transform_bypass_flag
+                            if (gb.readBool()) {
+                                // seq_scaling_matrix_present_flag
+                                var scaling_list_count = chroma_format_idc !== 3 ? 8 : 12;
+                                for (var i = 0; i < scaling_list_count; i++) {
+                                    if (gb.readBool()) {
+                                        // seq_scaling_list_present_flag
+                                        if (i < 6) {
+                                            SPSParser._skipScalingList(gb, 16);
+                                        } else {
+                                            SPSParser._skipScalingList(gb, 64);
+                                        }
+                                    }
+                                }
                             }
                         }
+                        gb.readUEG(); // log2_max_frame_num_minus4
+                        var pic_order_cnt_type = gb.readUEG();
+                        if (pic_order_cnt_type === 0) {
+                            gb.readUEG(); // log2_max_pic_order_cnt_lsb_minus_4
+                        } else if (pic_order_cnt_type === 1) {
+                            gb.readBits(1); // delta_pic_order_always_zero_flag
+                            gb.readSEG(); // offset_for_non_ref_pic
+                            gb.readSEG(); // offset_for_top_to_bottom_field
+                            var num_ref_frames_in_pic_order_cnt_cycle = gb.readUEG();
+                            for (var _i = 0; _i < num_ref_frames_in_pic_order_cnt_cycle; _i++) {
+                                gb.readSEG(); // offset_for_ref_frame
+                            }
+                        }
+                        var ref_frames = gb.readUEG(); // max_num_ref_frames
+                        gb.readBits(1); // gaps_in_frame_num_value_allowed_flag
+
+                        var pic_width_in_mbs_minus1 = gb.readUEG();
+                        var pic_height_in_map_units_minus1 = gb.readUEG();
+
+                        var frame_mbs_only_flag = gb.readBits(1);
+                        if (frame_mbs_only_flag === 0) {
+                            gb.readBits(1); // mb_adaptive_frame_field_flag
+                        }
+                        gb.readBits(1); // direct_8x8_inference_flag
+
+                        var frame_crop_left_offset = 0;
+                        var frame_crop_right_offset = 0;
+                        var frame_crop_top_offset = 0;
+                        var frame_crop_bottom_offset = 0;
+
+                        var frame_cropping_flag = gb.readBool();
+                        if (frame_cropping_flag) {
+                            frame_crop_left_offset = gb.readUEG();
+                            frame_crop_right_offset = gb.readUEG();
+                            frame_crop_top_offset = gb.readUEG();
+                            frame_crop_bottom_offset = gb.readUEG();
+                        }
+
+                        var sar_width = 1,
+                            sar_height = 1;
+                        var fps = 0,
+                            fps_fixed = true,
+                            fps_num = 0,
+                            fps_den = 0;
+
+                        var vui_parameters_present_flag = gb.readBool();
+                        if (vui_parameters_present_flag) {
+                            if (gb.readBool()) {
+                                // aspect_ratio_info_present_flag
+                                var aspect_ratio_idc = gb.readByte();
+                                var sar_w_table = [1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2];
+                                var sar_h_table = [1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1];
+
+                                if (aspect_ratio_idc > 0 && aspect_ratio_idc < 16) {
+                                    sar_width = sar_w_table[aspect_ratio_idc - 1];
+                                    sar_height = sar_h_table[aspect_ratio_idc - 1];
+                                } else if (aspect_ratio_idc === 255) {
+                                    sar_width = gb.readByte() << 8 | gb.readByte();
+                                    sar_height = gb.readByte() << 8 | gb.readByte();
+                                }
+                            }
+
+                            if (gb.readBool()) {
+                                // overscan_info_present_flag
+                                gb.readBool(); // overscan_appropriate_flag
+                            }
+                            if (gb.readBool()) {
+                                // video_signal_type_present_flag
+                                gb.readBits(4); // video_format & video_full_range_flag
+                                if (gb.readBool()) {
+                                    // colour_description_present_flag
+                                    gb.readBits(24); // colour_primaries & transfer_characteristics & matrix_coefficients
+                                }
+                            }
+                            if (gb.readBool()) {
+                                // chroma_loc_info_present_flag
+                                gb.readUEG(); // chroma_sample_loc_type_top_field
+                                gb.readUEG(); // chroma_sample_loc_type_bottom_field
+                            }
+                            if (gb.readBool()) {
+                                // timing_info_present_flag
+                                var num_units_in_tick = gb.readBits(32);
+                                var time_scale = gb.readBits(32);
+                                fps_fixed = gb.readBool(); // fixed_frame_rate_flag
+
+                                fps_num = time_scale;
+                                fps_den = num_units_in_tick * 2;
+                                fps = fps_num / fps_den;
+                            }
+                        }
+
+                        var sarScale = 1;
+                        if (sar_width !== 1 || sar_height !== 1) {
+                            sarScale = sar_width / sar_height;
+                        }
+
+                        var crop_unit_x = 0,
+                            crop_unit_y = 0;
+                        if (chroma_format_idc === 0) {
+                            crop_unit_x = 1;
+                            crop_unit_y = 2 - frame_mbs_only_flag;
+                        } else {
+                            var sub_wc = chroma_format_idc === 3 ? 1 : 2;
+                            var sub_hc = chroma_format_idc === 1 ? 2 : 1;
+                            crop_unit_x = sub_wc;
+                            crop_unit_y = sub_hc * (2 - frame_mbs_only_flag);
+                        }
+
+                        var codec_width = (pic_width_in_mbs_minus1 + 1) * 16;
+                        var codec_height = (2 - frame_mbs_only_flag) * ((pic_height_in_map_units_minus1 + 1) * 16);
+
+                        codec_width -= (frame_crop_left_offset + frame_crop_right_offset) * crop_unit_x;
+                        codec_height -= (frame_crop_top_offset + frame_crop_bottom_offset) * crop_unit_y;
+
+                        var present_width = Math.ceil(codec_width * sarScale);
+
+                        gb.destroy();
+                        gb = null;
+
+                        return {
+                            profile_string: profile_string, // baseline, high, high10, ...
+                            level_string: level_string, // 3, 3.1, 4, 4.1, 5, 5.1, ...
+                            bit_depth: bit_depth, // 8bit, 10bit, ...
+                            ref_frames: ref_frames,
+                            chroma_format: chroma_format, // 4:2:0, 4:2:2, ...
+                            chroma_format_string: SPSParser.getChromaFormatString(chroma_format),
+
+                            frame_rate: {
+                                fixed: fps_fixed,
+                                fps: fps,
+                                fps_den: fps_den,
+                                fps_num: fps_num
+                            },
+
+                            sar_ratio: {
+                                width: sar_width,
+                                height: sar_height
+                            },
+
+                            codec_size: {
+                                width: codec_width,
+                                height: codec_height
+                            },
+
+                            present_size: {
+                                width: present_width,
+                                height: codec_height
+                            }
+                        };
                     }
-                }
-            }
-            gb.readUEG(); // log2_max_frame_num_minus4
-            var pic_order_cnt_type = gb.readUEG();
-            if (pic_order_cnt_type === 0) {
-                gb.readUEG(); // log2_max_pic_order_cnt_lsb_minus_4
-            } else if (pic_order_cnt_type === 1) {
-                gb.readBits(1); // delta_pic_order_always_zero_flag
-                gb.readSEG(); // offset_for_non_ref_pic
-                gb.readSEG(); // offset_for_top_to_bottom_field
-                var num_ref_frames_in_pic_order_cnt_cycle = gb.readUEG();
-                for (var _i = 0; _i < num_ref_frames_in_pic_order_cnt_cycle; _i++) {
-                    gb.readSEG(); // offset_for_ref_frame
-                }
-            }
-            var ref_frames = gb.readUEG(); // max_num_ref_frames
-            gb.readBits(1); // gaps_in_frame_num_value_allowed_flag
-
-            var pic_width_in_mbs_minus1 = gb.readUEG();
-            var pic_height_in_map_units_minus1 = gb.readUEG();
-
-            var frame_mbs_only_flag = gb.readBits(1);
-            if (frame_mbs_only_flag === 0) {
-                gb.readBits(1); // mb_adaptive_frame_field_flag
-            }
-            gb.readBits(1); // direct_8x8_inference_flag
-
-            var frame_crop_left_offset = 0;
-            var frame_crop_right_offset = 0;
-            var frame_crop_top_offset = 0;
-            var frame_crop_bottom_offset = 0;
-
-            var frame_cropping_flag = gb.readBool();
-            if (frame_cropping_flag) {
-                frame_crop_left_offset = gb.readUEG();
-                frame_crop_right_offset = gb.readUEG();
-                frame_crop_top_offset = gb.readUEG();
-                frame_crop_bottom_offset = gb.readUEG();
-            }
-
-            var sar_width = 1,
-                sar_height = 1;
-            var fps = 0,
-                fps_fixed = true,
-                fps_num = 0,
-                fps_den = 0;
-
-            var vui_parameters_present_flag = gb.readBool();
-            if (vui_parameters_present_flag) {
-                if (gb.readBool()) {
-                    // aspect_ratio_info_present_flag
-                    var aspect_ratio_idc = gb.readByte();
-                    var sar_w_table = [1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2];
-                    var sar_h_table = [1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1];
-
-                    if (aspect_ratio_idc > 0 && aspect_ratio_idc < 16) {
-                        sar_width = sar_w_table[aspect_ratio_idc - 1];
-                        sar_height = sar_h_table[aspect_ratio_idc - 1];
-                    } else if (aspect_ratio_idc === 255) {
-                        sar_width = gb.readByte() << 8 | gb.readByte();
-                        sar_height = gb.readByte() << 8 | gb.readByte();
+                }, {
+                    key: '_skipScalingList',
+                    value: function _skipScalingList(gb, count) {
+                        var last_scale = 8,
+                            next_scale = 8;
+                        var delta_scale = 0;
+                        for (var i = 0; i < count; i++) {
+                            if (next_scale !== 0) {
+                                delta_scale = gb.readSEG();
+                                next_scale = (last_scale + delta_scale + 256) % 256;
+                            }
+                            last_scale = next_scale === 0 ? last_scale : next_scale;
+                        }
                     }
-                }
-
-                if (gb.readBool()) {
-                    // overscan_info_present_flag
-                    gb.readBool(); // overscan_appropriate_flag
-                }
-                if (gb.readBool()) {
-                    // video_signal_type_present_flag
-                    gb.readBits(4); // video_format & video_full_range_flag
-                    if (gb.readBool()) {
-                        // colour_description_present_flag
-                        gb.readBits(24); // colour_primaries & transfer_characteristics & matrix_coefficients
+                }, {
+                    key: 'getProfileString',
+                    value: function getProfileString(profile_idc) {
+                        switch (profile_idc) {
+                            case 66:
+                                return 'Baseline';
+                            case 77:
+                                return 'Main';
+                            case 88:
+                                return 'Extended';
+                            case 100:
+                                return 'High';
+                            case 110:
+                                return 'High10';
+                            case 122:
+                                return 'High422';
+                            case 244:
+                                return 'High444';
+                            default:
+                                return 'Unknown';
+                        }
                     }
-                }
-                if (gb.readBool()) {
-                    // chroma_loc_info_present_flag
-                    gb.readUEG(); // chroma_sample_loc_type_top_field
-                    gb.readUEG(); // chroma_sample_loc_type_bottom_field
-                }
-                if (gb.readBool()) {
-                    // timing_info_present_flag
-                    var num_units_in_tick = gb.readBits(32);
-                    var time_scale = gb.readBits(32);
-                    fps_fixed = gb.readBool(); // fixed_frame_rate_flag
+                }, {
+                    key: 'getLevelString',
+                    value: function getLevelString(level_idc) {
+                        return (level_idc / 10).toFixed(1);
+                    }
+                }, {
+                    key: 'getChromaFormatString',
+                    value: function getChromaFormatString(chroma) {
+                        switch (chroma) {
+                            case 420:
+                                return '4:2:0';
+                            case 422:
+                                return '4:2:2';
+                            case 444:
+                                return '4:4:4';
+                            default:
+                                return 'Unknown';
+                        }
+                    }
+                }]);
 
-                    fps_num = time_scale;
-                    fps_den = num_units_in_tick * 2;
-                    fps = fps_num / fps_den;
-                }
-            }
+                return SPSParser;
+            }();
 
-            var sarScale = 1;
-            if (sar_width !== 1 || sar_height !== 1) {
-                sarScale = sar_width / sar_height;
-            }
+            exports.default = SPSParser;
 
-            var crop_unit_x = 0,
-                crop_unit_y = 0;
-            if (chroma_format_idc === 0) {
-                crop_unit_x = 1;
-                crop_unit_y = 2 - frame_mbs_only_flag;
-            } else {
-                var sub_wc = chroma_format_idc === 3 ? 1 : 2;
-                var sub_hc = chroma_format_idc === 1 ? 2 : 1;
-                crop_unit_x = sub_wc;
-                crop_unit_y = sub_hc * (2 - frame_mbs_only_flag);
-            }
+        }, { "./exp-golomb.js": 17 }], 20: [function (_dereq_, module, exports) {
+            'use strict';
 
-            var codec_width = (pic_width_in_mbs_minus1 + 1) * 16;
-            var codec_height = (2 - frame_mbs_only_flag) * ((pic_height_in_map_units_minus1 + 1) * 16);
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
 
-            codec_width -= (frame_crop_left_offset + frame_crop_right_offset) * crop_unit_x;
-            codec_height -= (frame_crop_top_offset + frame_crop_bottom_offset) * crop_unit_y;
-
-            var present_width = Math.ceil(codec_width * sarScale);
-
-            gb.destroy();
-            gb = null;
-
-            return {
-                profile_string: profile_string, // baseline, high, high10, ...
-                level_string: level_string, // 3, 3.1, 4, 4.1, 5, 5.1, ...
-                bit_depth: bit_depth, // 8bit, 10bit, ...
-                ref_frames: ref_frames,
-                chroma_format: chroma_format, // 4:2:0, 4:2:2, ...
-                chroma_format_string: SPSParser.getChromaFormatString(chroma_format),
-
-                frame_rate: {
-                    fixed: fps_fixed,
-                    fps: fps,
-                    fps_den: fps_den,
-                    fps_num: fps_num
-                },
-
-                sar_ratio: {
-                    width: sar_width,
-                    height: sar_height
-                },
-
-                codec_size: {
-                    width: codec_width,
-                    height: codec_height
-                },
-
-                present_size: {
-                    width: present_width,
-                    height: codec_height
-                }
-            };
-        }
-    }, {
-        key: '_skipScalingList',
-        value: function _skipScalingList(gb, count) {
-            var last_scale = 8,
-                next_scale = 8;
-            var delta_scale = 0;
-            for (var i = 0; i < count; i++) {
-                if (next_scale !== 0) {
-                    delta_scale = gb.readSEG();
-                    next_scale = (last_scale + delta_scale + 256) % 256;
-                }
-                last_scale = next_scale === 0 ? last_scale : next_scale;
-            }
-        }
-    }, {
-        key: 'getProfileString',
-        value: function getProfileString(profile_idc) {
-            switch (profile_idc) {
-                case 66:
-                    return 'Baseline';
-                case 77:
-                    return 'Main';
-                case 88:
-                    return 'Extended';
-                case 100:
-                    return 'High';
-                case 110:
-                    return 'High10';
-                case 122:
-                    return 'High422';
-                case 244:
-                    return 'High444';
-                default:
-                    return 'Unknown';
-            }
-        }
-    }, {
-        key: 'getLevelString',
-        value: function getLevelString(level_idc) {
-            return (level_idc / 10).toFixed(1);
-        }
-    }, {
-        key: 'getChromaFormatString',
-        value: function getChromaFormatString(chroma) {
-            switch (chroma) {
-                case 420:
-                    return '4:2:0';
-                case 422:
-                    return '4:2:2';
-                case 444:
-                    return '4:4:4';
-                default:
-                    return 'Unknown';
-            }
-        }
-    }]);
-
-    return SPSParser;
-}();
-
-exports.default = SPSParser;
-
-},{"./exp-golomb.js":17}],20:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; /*
+            var _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; }; /*
                                                                                                                                                                                                                                                                                * Copyright (C) 2016 Bilibili. All Rights Reserved.
                                                                                                                                                                                                                                                                                *
                                                                                                                                                                                                                                                                                * @author zheng qian <xqq@xqq.im>
@@ -6057,140 +6068,140 @@
                                                                                                                                                                                                                                                                                * limitations under the License.
                                                                                                                                                                                                                                                                                */
 
-var _polyfill = _dereq_('./utils/polyfill.js');
+            var _polyfill = _dereq_('./utils/polyfill.js');
 
-var _polyfill2 = _interopRequireDefault(_polyfill);
+            var _polyfill2 = _interopRequireDefault(_polyfill);
 
-var _features = _dereq_('./core/features.js');
+            var _features = _dereq_('./core/features.js');
 
-var _features2 = _interopRequireDefault(_features);
+            var _features2 = _interopRequireDefault(_features);
 
-var _loader = _dereq_('./io/loader.js');
+            var _loader = _dereq_('./io/loader.js');
 
-var _flvPlayer = _dereq_('./player/flv-player.js');
+            var _flvPlayer = _dereq_('./player/flv-player.js');
 
-var _flvPlayer2 = _interopRequireDefault(_flvPlayer);
+            var _flvPlayer2 = _interopRequireDefault(_flvPlayer);
 
-var _nativePlayer = _dereq_('./player/native-player.js');
+            var _nativePlayer = _dereq_('./player/native-player.js');
 
-var _nativePlayer2 = _interopRequireDefault(_nativePlayer);
+            var _nativePlayer2 = _interopRequireDefault(_nativePlayer);
 
-var _playerEvents = _dereq_('./player/player-events.js');
+            var _playerEvents = _dereq_('./player/player-events.js');
 
-var _playerEvents2 = _interopRequireDefault(_playerEvents);
+            var _playerEvents2 = _interopRequireDefault(_playerEvents);
 
-var _playerErrors = _dereq_('./player/player-errors.js');
+            var _playerErrors = _dereq_('./player/player-errors.js');
 
-var _loggingControl = _dereq_('./utils/logging-control.js');
+            var _loggingControl = _dereq_('./utils/logging-control.js');
 
-var _loggingControl2 = _interopRequireDefault(_loggingControl);
+            var _loggingControl2 = _interopRequireDefault(_loggingControl);
 
-var _exception = _dereq_('./utils/exception.js');
+            var _exception = _dereq_('./utils/exception.js');
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-// here are all the interfaces
+            // here are all the interfaces
 
-// install polyfills
-_polyfill2.default.install();
+            // install polyfills
+            _polyfill2.default.install();
 
-// factory method
-function createPlayer(mediaDataSource, optionalConfig) {
-    var mds = mediaDataSource;
-    if (mds == null || (typeof mds === 'undefined' ? 'undefined' : _typeof(mds)) !== 'object') {
-        throw new _exception.InvalidArgumentException('MediaDataSource must be an javascript object!');
-    }
+            // factory method
+            function createPlayer(mediaDataSource, optionalConfig) {
+                var mds = mediaDataSource;
+                if (mds == null || (typeof mds === 'undefined' ? 'undefined' : _typeof(mds)) !== 'object') {
+                    throw new _exception.InvalidArgumentException('MediaDataSource must be an javascript object!');
+                }
 
-    if (!mds.hasOwnProperty('type')) {
-        throw new _exception.InvalidArgumentException('MediaDataSource must has type field to indicate video file type!');
-    }
+                if (!mds.hasOwnProperty('type')) {
+                    throw new _exception.InvalidArgumentException('MediaDataSource must has type field to indicate video file type!');
+                }
 
-    switch (mds.type) {
-        case 'flv':
-            return new _flvPlayer2.default(mds, optionalConfig);
-        default:
-            return new _nativePlayer2.default(mds, optionalConfig);
-    }
-}
+                switch (mds.type) {
+                    case 'flv':
+                        return new _flvPlayer2.default(mds, optionalConfig);
+                    default:
+                        return new _nativePlayer2.default(mds, optionalConfig);
+                }
+            }
 
-// feature detection
-function isSupported() {
-    return _features2.default.supportMSEH264Playback();
-}
+            // feature detection
+            function isSupported() {
+                return _features2.default.supportMSEH264Playback();
+            }
 
-function getFeatureList() {
-    return _features2.default.getFeatureList();
-}
+            function getFeatureList() {
+                return _features2.default.getFeatureList();
+            }
 
-// interfaces
-var flvjs = {};
+            // interfaces
+            var flvjs = {};
 
-flvjs.createPlayer = createPlayer;
-flvjs.isSupported = isSupported;
-flvjs.getFeatureList = getFeatureList;
+            flvjs.createPlayer = createPlayer;
+            flvjs.isSupported = isSupported;
+            flvjs.getFeatureList = getFeatureList;
 
-flvjs.BaseLoader = _loader.BaseLoader;
-flvjs.LoaderStatus = _loader.LoaderStatus;
-flvjs.LoaderErrors = _loader.LoaderErrors;
+            flvjs.BaseLoader = _loader.BaseLoader;
+            flvjs.LoaderStatus = _loader.LoaderStatus;
+            flvjs.LoaderErrors = _loader.LoaderErrors;
 
-flvjs.Events = _playerEvents2.default;
-flvjs.ErrorTypes = _playerErrors.ErrorTypes;
-flvjs.ErrorDetails = _playerErrors.ErrorDetails;
+            flvjs.Events = _playerEvents2.default;
+            flvjs.ErrorTypes = _playerErrors.ErrorTypes;
+            flvjs.ErrorDetails = _playerErrors.ErrorDetails;
 
-flvjs.FlvPlayer = _flvPlayer2.default;
-flvjs.NativePlayer = _nativePlayer2.default;
-flvjs.LoggingControl = _loggingControl2.default;
+            flvjs.FlvPlayer = _flvPlayer2.default;
+            flvjs.NativePlayer = _nativePlayer2.default;
+            flvjs.LoggingControl = _loggingControl2.default;
 
-Object.defineProperty(flvjs, 'version', {
-    enumerable: true,
-    get: function get() {
-        // replaced by browserify-versionify transform
-        return '1.5.0';
-    }
-});
+            Object.defineProperty(flvjs, 'version', {
+                enumerable: true,
+                get: function get() {
+                    // replaced by browserify-versionify transform
+                    return '1.5.0';
+                }
+            });
 
-exports.default = flvjs;
+            exports.default = flvjs;
 
-},{"./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){
-'use strict';
+        }, { "./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) {
+            'use strict';
 
-// entry/index file
+            // entry/index file
 
-// make it compatible with browserify's umd wrapper
-module.exports = _dereq_('./flv.js').default;
+            // make it compatible with browserify's umd wrapper
+            module.exports = _dereq_('./flv.js').default;
 
-},{"./flv.js":20}],22:[function(_dereq_,module,exports){
-'use strict';
+        }, { "./flv.js": 20 }], 22: [function (_dereq_, module, exports) {
+            'use strict';
 
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
 
-var _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; };
+            var _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; };
 
-var _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); } };
+            var _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); } };
 
-var _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; }; }();
+            var _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; }; }();
 
-var _logger = _dereq_('../utils/logger.js');
+            var _logger = _dereq_('../utils/logger.js');
 
-var _logger2 = _interopRequireDefault(_logger);
+            var _logger2 = _interopRequireDefault(_logger);
 
-var _browser = _dereq_('../utils/browser.js');
+            var _browser = _dereq_('../utils/browser.js');
 
-var _browser2 = _interopRequireDefault(_browser);
+            var _browser2 = _interopRequireDefault(_browser);
 
-var _loader = _dereq_('./loader.js');
+            var _loader = _dereq_('./loader.js');
 
-var _exception = _dereq_('../utils/exception.js');
+            var _exception = _dereq_('../utils/exception.js');
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-function _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; }
+            function _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; }
 
-function _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; } /*
+            function _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; } /*
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * Copyright (C) 2016 Bilibili. All Rights Reserved.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 *
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * @author zheng qian <xqq@xqq.im>
@@ -6208,252 +6219,252 @@
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * limitations under the License.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 */
 
-/* fetch + stream IO loader. Currently working on chrome 43+.
- * fetch provides a better alternative http API to XMLHttpRequest
- *
- * fetch spec   https://fetch.spec.whatwg.org/
- * stream spec  https://streams.spec.whatwg.org/
- */
-var FetchStreamLoader = function (_BaseLoader) {
-    _inherits(FetchStreamLoader, _BaseLoader);
+            /* fetch + stream IO loader. Currently working on chrome 43+.
+             * fetch provides a better alternative http API to XMLHttpRequest
+             *
+             * fetch spec   https://fetch.spec.whatwg.org/
+             * stream spec  https://streams.spec.whatwg.org/
+             */
+            var FetchStreamLoader = function (_BaseLoader) {
+                _inherits(FetchStreamLoader, _BaseLoader);
 
-    _createClass(FetchStreamLoader, null, [{
-        key: 'isSupported',
-        value: function isSupported() {
-            try {
-                // fetch + stream is broken on Microsoft Edge. Disable before build 15048.
-                // see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8196907/
-                // Fixed in Jan 10, 2017. Build 15048+ removed from blacklist.
-                var isWorkWellEdge = _browser2.default.msedge && _browser2.default.version.minor >= 15048;
-                var browserNotBlacklisted = _browser2.default.msedge ? isWorkWellEdge : true;
-                return self.fetch && self.ReadableStream && browserNotBlacklisted;
-            } catch (e) {
-                return false;
-            }
-        }
-    }]);
-
-    function FetchStreamLoader(seekHandler, config) {
-        _classCallCheck(this, FetchStreamLoader);
-
-        var _this = _possibleConstructorReturn(this, (FetchStreamLoader.__proto__ || Object.getPrototypeOf(FetchStreamLoader)).call(this, 'fetch-stream-loader'));
-
-        _this.TAG = 'FetchStreamLoader';
-
-        _this._seekHandler = seekHandler;
-        _this._config = config;
-        _this._needStash = true;
-
-        _this._requestAbort = false;
-        _this._contentLength = null;
-        _this._receivedLength = 0;
-        return _this;
-    }
-
-    _createClass(FetchStreamLoader, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this.isWorking()) {
-                this.abort();
-            }
-            _get(FetchStreamLoader.prototype.__proto__ || Object.getPrototypeOf(FetchStreamLoader.prototype), 'destroy', this).call(this);
-        }
-    }, {
-        key: 'open',
-        value: function open(dataSource, range) {
-            var _this2 = this;
-
-            this._dataSource = dataSource;
-            this._range = range;
-
-            var sourceURL = dataSource.url;
-            if (this._config.reuseRedirectedURL && dataSource.redirectedURL != undefined) {
-                sourceURL = dataSource.redirectedURL;
-            }
-
-            var seekConfig = this._seekHandler.getConfig(sourceURL, range);
-
-            var headers = new self.Headers();
-
-            if (_typeof(seekConfig.headers) === 'object') {
-                var configHeaders = seekConfig.headers;
-                for (var key in configHeaders) {
-                    if (configHeaders.hasOwnProperty(key)) {
-                        headers.append(key, configHeaders[key]);
-                    }
-                }
-            }
-
-            var params = {
-                method: 'GET',
-                headers: headers,
-                mode: 'cors',
-                cache: 'default',
-                // The default policy of Fetch API in the whatwg standard
-                // Safari incorrectly indicates 'no-referrer' as default policy, fuck it
-                referrerPolicy: 'no-referrer-when-downgrade'
-            };
-
-            // add additional headers
-            if (_typeof(this._config.headers) === 'object') {
-                for (var _key in this._config.headers) {
-                    headers.append(_key, this._config.headers[_key]);
-                }
-            }
-
-            // cors is enabled by default
-            if (dataSource.cors === false) {
-                // no-cors means 'disregard cors policy', which can only be used in ServiceWorker
-                params.mode = 'same-origin';
-            }
-
-            // withCredentials is disabled by default
-            if (dataSource.withCredentials) {
-                params.credentials = 'include';
-            }
-
-            // referrerPolicy from config
-            if (dataSource.referrerPolicy) {
-                params.referrerPolicy = dataSource.referrerPolicy;
-            }
-
-            this._status = _loader.LoaderStatus.kConnecting;
-            self.fetch(seekConfig.url, params).then(function (res) {
-                if (_this2._requestAbort) {
-                    _this2._requestAbort = false;
-                    _this2._status = _loader.LoaderStatus.kIdle;
-                    return;
-                }
-                if (res.ok && res.status >= 200 && res.status <= 299) {
-                    if (res.url !== seekConfig.url) {
-                        if (_this2._onURLRedirect) {
-                            var redirectedURL = _this2._seekHandler.removeURLParameters(res.url);
-                            _this2._onURLRedirect(redirectedURL);
+                _createClass(FetchStreamLoader, null, [{
+                    key: 'isSupported',
+                    value: function isSupported() {
+                        try {
+                            // fetch + stream is broken on Microsoft Edge. Disable before build 15048.
+                            // see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8196907/
+                            // Fixed in Jan 10, 2017. Build 15048+ removed from blacklist.
+                            var isWorkWellEdge = _browser2.default.msedge && _browser2.default.version.minor >= 15048;
+                            var browserNotBlacklisted = _browser2.default.msedge ? isWorkWellEdge : true;
+                            return self.fetch && self.ReadableStream && browserNotBlacklisted;
+                        } catch (e) {
+                            return false;
                         }
                     }
+                }]);
 
-                    var lengthHeader = res.headers.get('Content-Length');
-                    if (lengthHeader != null) {
-                        _this2._contentLength = parseInt(lengthHeader);
-                        if (_this2._contentLength !== 0) {
-                            if (_this2._onContentLengthKnown) {
-                                _this2._onContentLengthKnown(_this2._contentLength);
+                function FetchStreamLoader(seekHandler, config) {
+                    _classCallCheck(this, FetchStreamLoader);
+
+                    var _this = _possibleConstructorReturn(this, (FetchStreamLoader.__proto__ || Object.getPrototypeOf(FetchStreamLoader)).call(this, 'fetch-stream-loader'));
+
+                    _this.TAG = 'FetchStreamLoader';
+
+                    _this._seekHandler = seekHandler;
+                    _this._config = config;
+                    _this._needStash = true;
+
+                    _this._requestAbort = false;
+                    _this._contentLength = null;
+                    _this._receivedLength = 0;
+                    return _this;
+                }
+
+                _createClass(FetchStreamLoader, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        if (this.isWorking()) {
+                            this.abort();
+                        }
+                        _get(FetchStreamLoader.prototype.__proto__ || Object.getPrototypeOf(FetchStreamLoader.prototype), 'destroy', this).call(this);
+                    }
+                }, {
+                    key: 'open',
+                    value: function open(dataSource, range) {
+                        var _this2 = this;
+
+                        this._dataSource = dataSource;
+                        this._range = range;
+
+                        var sourceURL = dataSource.url;
+                        if (this._config.reuseRedirectedURL && dataSource.redirectedURL != undefined) {
+                            sourceURL = dataSource.redirectedURL;
+                        }
+
+                        var seekConfig = this._seekHandler.getConfig(sourceURL, range);
+
+                        var headers = new self.Headers();
+
+                        if (_typeof(seekConfig.headers) === 'object') {
+                            var configHeaders = seekConfig.headers;
+                            for (var key in configHeaders) {
+                                if (configHeaders.hasOwnProperty(key)) {
+                                    headers.append(key, configHeaders[key]);
+                                }
                             }
                         }
-                    }
 
-                    return _this2._pump.call(_this2, res.body.getReader());
-                } else {
-                    _this2._status = _loader.LoaderStatus.kError;
-                    if (_this2._onError) {
-                        _this2._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: res.status, msg: res.statusText });
-                    } else {
-                        throw new _exception.RuntimeException('FetchStreamLoader: Http code invalid, ' + res.status + ' ' + res.statusText);
-                    }
-                }
-            }).catch(function (e) {
-                _this2._status = _loader.LoaderStatus.kError;
-                if (_this2._onError) {
-                    _this2._onError(_loader.LoaderErrors.EXCEPTION, { code: -1, msg: e.message });
-                } else {
-                    throw e;
-                }
-            });
-        }
-    }, {
-        key: 'abort',
-        value: function abort() {
-            this._requestAbort = true;
-        }
-    }, {
-        key: '_pump',
-        value: function _pump(reader) {
-            var _this3 = this;
+                        var params = {
+                            method: 'GET',
+                            headers: headers,
+                            mode: 'cors',
+                            cache: 'default',
+                            // The default policy of Fetch API in the whatwg standard
+                            // Safari incorrectly indicates 'no-referrer' as default policy, fuck it
+                            referrerPolicy: 'no-referrer-when-downgrade'
+                        };
 
-            // ReadableStreamReader
-            return reader.read().then(function (result) {
-                if (result.done) {
-                    // First check received length
-                    if (_this3._contentLength !== null && _this3._receivedLength < _this3._contentLength) {
-                        // Report Early-EOF
-                        _this3._status = _loader.LoaderStatus.kError;
-                        var type = _loader.LoaderErrors.EARLY_EOF;
-                        var info = { code: -1, msg: 'Fetch stream meet Early-EOF' };
-                        if (_this3._onError) {
-                            _this3._onError(type, info);
-                        } else {
-                            throw new _exception.RuntimeException(info.msg);
+                        // add additional headers
+                        if (_typeof(this._config.headers) === 'object') {
+                            for (var _key in this._config.headers) {
+                                headers.append(_key, this._config.headers[_key]);
+                            }
                         }
-                    } else {
-                        // OK. Download complete
-                        _this3._status = _loader.LoaderStatus.kComplete;
-                        if (_this3._onComplete) {
-                            _this3._onComplete(_this3._range.from, _this3._range.from + _this3._receivedLength - 1);
+
+                        // cors is enabled by default
+                        if (dataSource.cors === false) {
+                            // no-cors means 'disregard cors policy', which can only be used in ServiceWorker
+                            params.mode = 'same-origin';
                         }
+
+                        // withCredentials is disabled by default
+                        if (dataSource.withCredentials) {
+                            params.credentials = 'include';
+                        }
+
+                        // referrerPolicy from config
+                        if (dataSource.referrerPolicy) {
+                            params.referrerPolicy = dataSource.referrerPolicy;
+                        }
+
+                        this._status = _loader.LoaderStatus.kConnecting;
+                        self.fetch(seekConfig.url, params).then(function (res) {
+                            if (_this2._requestAbort) {
+                                _this2._requestAbort = false;
+                                _this2._status = _loader.LoaderStatus.kIdle;
+                                return;
+                            }
+                            if (res.ok && res.status >= 200 && res.status <= 299) {
+                                if (res.url !== seekConfig.url) {
+                                    if (_this2._onURLRedirect) {
+                                        var redirectedURL = _this2._seekHandler.removeURLParameters(res.url);
+                                        _this2._onURLRedirect(redirectedURL);
+                                    }
+                                }
+
+                                var lengthHeader = res.headers.get('Content-Length');
+                                if (lengthHeader != null) {
+                                    _this2._contentLength = parseInt(lengthHeader);
+                                    if (_this2._contentLength !== 0) {
+                                        if (_this2._onContentLengthKnown) {
+                                            _this2._onContentLengthKnown(_this2._contentLength);
+                                        }
+                                    }
+                                }
+
+                                return _this2._pump.call(_this2, res.body.getReader());
+                            } else {
+                                _this2._status = _loader.LoaderStatus.kError;
+                                if (_this2._onError) {
+                                    _this2._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: res.status, msg: res.statusText });
+                                } else {
+                                    throw new _exception.RuntimeException('FetchStreamLoader: Http code invalid, ' + res.status + ' ' + res.statusText);
+                                }
+                            }
+                        }).catch(function (e) {
+                            _this2._status = _loader.LoaderStatus.kError;
+                            if (_this2._onError) {
+                                _this2._onError(_loader.LoaderErrors.EXCEPTION, { code: -1, msg: e.message });
+                            } else {
+                                throw e;
+                            }
+                        });
                     }
-                } else {
-                    if (_this3._requestAbort === true) {
-                        _this3._requestAbort = false;
-                        _this3._status = _loader.LoaderStatus.kComplete;
-                        return reader.cancel();
+                }, {
+                    key: 'abort',
+                    value: function abort() {
+                        this._requestAbort = true;
                     }
+                }, {
+                    key: '_pump',
+                    value: function _pump(reader) {
+                        var _this3 = this;
 
-                    _this3._status = _loader.LoaderStatus.kBuffering;
+                        // ReadableStreamReader
+                        return reader.read().then(function (result) {
+                            if (result.done) {
+                                // First check received length
+                                if (_this3._contentLength !== null && _this3._receivedLength < _this3._contentLength) {
+                                    // Report Early-EOF
+                                    _this3._status = _loader.LoaderStatus.kError;
+                                    var type = _loader.LoaderErrors.EARLY_EOF;
+                                    var info = { code: -1, msg: 'Fetch stream meet Early-EOF' };
+                                    if (_this3._onError) {
+                                        _this3._onError(type, info);
+                                    } else {
+                                        throw new _exception.RuntimeException(info.msg);
+                                    }
+                                } else {
+                                    // OK. Download complete
+                                    _this3._status = _loader.LoaderStatus.kComplete;
+                                    if (_this3._onComplete) {
+                                        _this3._onComplete(_this3._range.from, _this3._range.from + _this3._receivedLength - 1);
+                                    }
+                                }
+                            } else {
+                                if (_this3._requestAbort === true) {
+                                    _this3._requestAbort = false;
+                                    _this3._status = _loader.LoaderStatus.kComplete;
+                                    return reader.cancel();
+                                }
 
-                    var chunk = result.value.buffer;
-                    var byteStart = _this3._range.from + _this3._receivedLength;
-                    _this3._receivedLength += chunk.byteLength;
+                                _this3._status = _loader.LoaderStatus.kBuffering;
 
-                    if (_this3._onDataArrival) {
-                        _this3._onDataArrival(chunk, byteStart, _this3._receivedLength);
+                                var chunk = result.value.buffer;
+                                var byteStart = _this3._range.from + _this3._receivedLength;
+                                _this3._receivedLength += chunk.byteLength;
+
+                                if (_this3._onDataArrival) {
+                                    _this3._onDataArrival(chunk, byteStart, _this3._receivedLength);
+                                }
+
+                                _this3._pump(reader);
+                            }
+                        }).catch(function (e) {
+                            if (e.code === 11 && _browser2.default.msedge) {
+                                // InvalidStateError on Microsoft Edge
+                                // Workaround: Edge may throw InvalidStateError after ReadableStreamReader.cancel() call
+                                // Ignore the unknown exception.
+                                // Related issue: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11265202/
+                                return;
+                            }
+
+                            _this3._status = _loader.LoaderStatus.kError;
+                            var type = 0;
+                            var info = null;
+
+                            if ((e.code === 19 || e.message === 'network error') && ( // NETWORK_ERR
+                                _this3._contentLength === null || _this3._contentLength !== null && _this3._receivedLength < _this3._contentLength)) {
+                                type = _loader.LoaderErrors.EARLY_EOF;
+                                info = { code: e.code, msg: 'Fetch stream meet Early-EOF' };
+                            } else {
+                                type = _loader.LoaderErrors.EXCEPTION;
+                                info = { code: e.code, msg: e.message };
+                            }
+
+                            if (_this3._onError) {
+                                _this3._onError(type, info);
+                            } else {
+                                throw new _exception.RuntimeException(info.msg);
+                            }
+                        });
                     }
+                }]);
 
-                    _this3._pump(reader);
-                }
-            }).catch(function (e) {
-                if (e.code === 11 && _browser2.default.msedge) {
-                    // InvalidStateError on Microsoft Edge
-                    // Workaround: Edge may throw InvalidStateError after ReadableStreamReader.cancel() call
-                    // Ignore the unknown exception.
-                    // Related issue: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11265202/
-                    return;
-                }
+                return FetchStreamLoader;
+            }(_loader.BaseLoader);
 
-                _this3._status = _loader.LoaderStatus.kError;
-                var type = 0;
-                var info = null;
+            exports.default = FetchStreamLoader;
 
-                if ((e.code === 19 || e.message === 'network error') && ( // NETWORK_ERR
-                _this3._contentLength === null || _this3._contentLength !== null && _this3._receivedLength < _this3._contentLength)) {
-                    type = _loader.LoaderErrors.EARLY_EOF;
-                    info = { code: e.code, msg: 'Fetch stream meet Early-EOF' };
-                } else {
-                    type = _loader.LoaderErrors.EXCEPTION;
-                    info = { code: e.code, msg: e.message };
-                }
+        }, { "../utils/browser.js": 39, "../utils/exception.js": 40, "../utils/logger.js": 41, "./loader.js": 24 }], 23: [function (_dereq_, module, exports) {
+            'use strict';
 
-                if (_this3._onError) {
-                    _this3._onError(type, info);
-                } else {
-                    throw new _exception.RuntimeException(info.msg);
-                }
+            Object.defineProperty(exports, "__esModule", {
+                value: true
             });
-        }
-    }]);
 
-    return FetchStreamLoader;
-}(_loader.BaseLoader);
-
-exports.default = FetchStreamLoader;
-
-},{"../utils/browser.js":39,"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24}],23:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
+            var _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; }; }(); /*
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * Copyright (C) 2016 Bilibili. All Rights Reserved.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       *
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * @author zheng qian <xqq@xqq.im>
@@ -6471,728 +6482,728 @@
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * limitations under the License.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       */
 
-var _logger = _dereq_('../utils/logger.js');
+            var _logger = _dereq_('../utils/logger.js');
 
-var _logger2 = _interopRequireDefault(_logger);
+            var _logger2 = _interopRequireDefault(_logger);
 
-var _speedSampler = _dereq_('./speed-sampler.js');
+            var _speedSampler = _dereq_('./speed-sampler.js');
 
-var _speedSampler2 = _interopRequireDefault(_speedSampler);
+            var _speedSampler2 = _interopRequireDefault(_speedSampler);
 
-var _loader = _dereq_('./loader.js');
+            var _loader = _dereq_('./loader.js');
 
-var _fetchStreamLoader = _dereq_('./fetch-stream-loader.js');
+            var _fetchStreamLoader = _dereq_('./fetch-stream-loader.js');
 
-var _fetchStreamLoader2 = _interopRequireDefault(_fetchStreamLoader);
+            var _fetchStreamLoader2 = _interopRequireDefault(_fetchStreamLoader);
 
-var _xhrMozChunkedLoader = _dereq_('./xhr-moz-chunked-loader.js');
+            var _xhrMozChunkedLoader = _dereq_('./xhr-moz-chunked-loader.js');
 
-var _xhrMozChunkedLoader2 = _interopRequireDefault(_xhrMozChunkedLoader);
+            var _xhrMozChunkedLoader2 = _interopRequireDefault(_xhrMozChunkedLoader);
 
-var _xhrMsstreamLoader = _dereq_('./xhr-msstream-loader.js');
+            var _xhrMsstreamLoader = _dereq_('./xhr-msstream-loader.js');
 
-var _xhrMsstreamLoader2 = _interopRequireDefault(_xhrMsstreamLoader);
+            var _xhrMsstreamLoader2 = _interopRequireDefault(_xhrMsstreamLoader);
 
-var _xhrRangeLoader = _dereq_('./xhr-range-loader.js');
+            var _xhrRangeLoader = _dereq_('./xhr-range-loader.js');
 
-var _xhrRangeLoader2 = _interopRequireDefault(_xhrRangeLoader);
+            var _xhrRangeLoader2 = _interopRequireDefault(_xhrRangeLoader);
 
-var _websocketLoader = _dereq_('./websocket-loader.js');
+            var _websocketLoader = _dereq_('./websocket-loader.js');
 
-var _websocketLoader2 = _interopRequireDefault(_websocketLoader);
+            var _websocketLoader2 = _interopRequireDefault(_websocketLoader);
 
-var _rangeSeekHandler = _dereq_('./range-seek-handler.js');
+            var _rangeSeekHandler = _dereq_('./range-seek-handler.js');
 
-var _rangeSeekHandler2 = _interopRequireDefault(_rangeSeekHandler);
+            var _rangeSeekHandler2 = _interopRequireDefault(_rangeSeekHandler);
 
-var _paramSeekHandler = _dereq_('./param-seek-handler.js');
+            var _paramSeekHandler = _dereq_('./param-seek-handler.js');
 
-var _paramSeekHandler2 = _interopRequireDefault(_paramSeekHandler);
+            var _paramSeekHandler2 = _interopRequireDefault(_paramSeekHandler);
 
-var _exception = _dereq_('../utils/exception.js');
+            var _exception = _dereq_('../utils/exception.js');
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-/**
- * DataSource: {
- *     url: string,
- *     filesize: number,
- *     cors: boolean,
- *     withCredentials: boolean
- * }
- * 
- */
+            /**
+             * DataSource: {
+             *     url: string,
+             *     filesize: number,
+             *     cors: boolean,
+             *     withCredentials: boolean
+             * }
+             * 
+             */
 
-// Manage IO Loaders
-var IOController = function () {
-    function IOController(dataSource, config, extraData) {
-        _classCallCheck(this, IOController);
+            // Manage IO Loaders
+            var IOController = function () {
+                function IOController(dataSource, config, extraData) {
+                    _classCallCheck(this, IOController);
 
-        this.TAG = 'IOController';
+                    this.TAG = 'IOController';
 
-        this._config = config;
-        this._extraData = extraData;
+                    this._config = config;
+                    this._extraData = extraData;
 
-        this._stashInitialSize = 1024 * 384; // default initial size: 384KB
-        if (config.stashInitialSize != undefined && config.stashInitialSize > 0) {
-            // apply from config
-            this._stashInitialSize = config.stashInitialSize;
-        }
+                    this._stashInitialSize = 1024 * 384; // default initial size: 384KB
+                    if (config.stashInitialSize != undefined && config.stashInitialSize > 0) {
+                        // apply from config
+                        this._stashInitialSize = config.stashInitialSize;
+                    }
 
-        this._stashUsed = 0;
-        this._stashSize = this._stashInitialSize;
-        this._bufferSize = 1024 * 1024 * 3; // initial size: 3MB
-        this._stashBuffer = new ArrayBuffer(this._bufferSize);
-        this._stashByteStart = 0;
-        this._enableStash = true;
-        if (config.enableStashBuffer === false) {
-            this._enableStash = false;
-        }
+                    this._stashUsed = 0;
+                    this._stashSize = this._stashInitialSize;
+                    this._bufferSize = 1024 * 1024 * 3; // initial size: 3MB
+                    this._stashBuffer = new ArrayBuffer(this._bufferSize);
+                    this._stashByteStart = 0;
+                    this._enableStash = true;
+                    if (config.enableStashBuffer === false) {
+                        this._enableStash = false;
+                    }
 
-        this._loader = null;
-        this._loaderClass = null;
-        this._seekHandler = null;
+                    this._loader = null;
+                    this._loaderClass = null;
+                    this._seekHandler = null;
 
-        this._dataSource = dataSource;
-        this._isWebSocketURL = /wss?:\/\/(.+?)/.test(dataSource.url);
-        this._refTotalLength = dataSource.filesize ? dataSource.filesize : null;
-        this._totalLength = this._refTotalLength;
-        this._fullRequestFlag = false;
-        this._currentRange = null;
-        this._redirectedURL = null;
+                    this._dataSource = dataSource;
+                    this._isWebSocketURL = /wss?:\/\/(.+?)/.test(dataSource.url);
+                    this._refTotalLength = dataSource.filesize ? dataSource.filesize : null;
+                    this._totalLength = this._refTotalLength;
+                    this._fullRequestFlag = false;
+                    this._currentRange = null;
+                    this._redirectedURL = null;
 
-        this._speedNormalized = 0;
-        this._speedSampler = new _speedSampler2.default();
-        this._speedNormalizeList = [64, 128, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096];
+                    this._speedNormalized = 0;
+                    this._speedSampler = new _speedSampler2.default();
+                    this._speedNormalizeList = [64, 128, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096];
 
-        this._isEarlyEofReconnecting = false;
+                    this._isEarlyEofReconnecting = false;
 
-        this._paused = false;
-        this._resumeFrom = 0;
+                    this._paused = false;
+                    this._resumeFrom = 0;
 
-        this._onDataArrival = null;
-        this._onSeeked = null;
-        this._onError = null;
-        this._onComplete = null;
-        this._onRedirect = null;
-        this._onRecoveredEarlyEof = null;
+                    this._onDataArrival = null;
+                    this._onSeeked = null;
+                    this._onError = null;
+                    this._onComplete = null;
+                    this._onRedirect = null;
+                    this._onRecoveredEarlyEof = null;
 
-        this._selectSeekHandler();
-        this._selectLoader();
-        this._createLoader();
-    }
-
-    _createClass(IOController, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this._loader.isWorking()) {
-                this._loader.abort();
-            }
-            this._loader.destroy();
-            this._loader = null;
-            this._loaderClass = null;
-            this._dataSource = null;
-            this._stashBuffer = null;
-            this._stashUsed = this._stashSize = this._bufferSize = this._stashByteStart = 0;
-            this._currentRange = null;
-            this._speedSampler = null;
-
-            this._isEarlyEofReconnecting = false;
-
-            this._onDataArrival = null;
-            this._onSeeked = null;
-            this._onError = null;
-            this._onComplete = null;
-            this._onRedirect = null;
-            this._onRecoveredEarlyEof = null;
-
-            this._extraData = null;
-        }
-    }, {
-        key: 'isWorking',
-        value: function isWorking() {
-            return this._loader && this._loader.isWorking() && !this._paused;
-        }
-    }, {
-        key: 'isPaused',
-        value: function isPaused() {
-            return this._paused;
-        }
-    }, {
-        key: '_selectSeekHandler',
-        value: function _selectSeekHandler() {
-            var config = this._config;
-
-            if (config.seekType === 'range') {
-                this._seekHandler = new _rangeSeekHandler2.default(this._config.rangeLoadZeroStart);
-            } else if (config.seekType === 'param') {
-                var paramStart = config.seekParamStart || 'bstart';
-                var paramEnd = config.seekParamEnd || 'bend';
-
-                this._seekHandler = new _paramSeekHandler2.default(paramStart, paramEnd);
-            } else if (config.seekType === 'custom') {
-                if (typeof config.customSeekHandler !== 'function') {
-                    throw new _exception.InvalidArgumentException('Custom seekType specified in config but invalid customSeekHandler!');
+                    this._selectSeekHandler();
+                    this._selectLoader();
+                    this._createLoader();
                 }
-                this._seekHandler = new config.customSeekHandler();
-            } else {
-                throw new _exception.InvalidArgumentException('Invalid seekType in config: ' + config.seekType);
-            }
-        }
-    }, {
-        key: '_selectLoader',
-        value: function _selectLoader() {
-            if (this._config.customLoader != null) {
-                this._loaderClass = this._config.customLoader;
-            } else if (this._isWebSocketURL) {
-                this._loaderClass = _websocketLoader2.default;
-            } else if (_fetchStreamLoader2.default.isSupported()) {
-                this._loaderClass = _fetchStreamLoader2.default;
-            } else if (_xhrMozChunkedLoader2.default.isSupported()) {
-                this._loaderClass = _xhrMozChunkedLoader2.default;
-            } else if (_xhrRangeLoader2.default.isSupported()) {
-                this._loaderClass = _xhrRangeLoader2.default;
-            } else {
-                throw new _exception.RuntimeException('Your browser doesn\'t support xhr with arraybuffer responseType!');
-            }
-        }
-    }, {
-        key: '_createLoader',
-        value: function _createLoader() {
-            this._loader = new this._loaderClass(this._seekHandler, this._config);
-            if (this._loader.needStashBuffer === false) {
-                this._enableStash = false;
-            }
-            this._loader.onContentLengthKnown = this._onContentLengthKnown.bind(this);
-            this._loader.onURLRedirect = this._onURLRedirect.bind(this);
-            this._loader.onDataArrival = this._onLoaderChunkArrival.bind(this);
-            this._loader.onComplete = this._onLoaderComplete.bind(this);
-            this._loader.onError = this._onLoaderError.bind(this);
-        }
-    }, {
-        key: 'open',
-        value: function open(optionalFrom) {
-            this._currentRange = { from: 0, to: -1 };
-            if (optionalFrom) {
-                this._currentRange.from = optionalFrom;
-            }
 
-            this._speedSampler.reset();
-            if (!optionalFrom) {
-                this._fullRequestFlag = true;
-            }
-
-            this._loader.open(this._dataSource, Object.assign({}, this._currentRange));
-        }
-    }, {
-        key: 'abort',
-        value: function abort() {
-            this._loader.abort();
-
-            if (this._paused) {
-                this._paused = false;
-                this._resumeFrom = 0;
-            }
-        }
-    }, {
-        key: 'pause',
-        value: function pause() {
-            if (this.isWorking()) {
-                this._loader.abort();
-
-                if (this._stashUsed !== 0) {
-                    this._resumeFrom = this._stashByteStart;
-                    this._currentRange.to = this._stashByteStart - 1;
-                } else {
-                    this._resumeFrom = this._currentRange.to + 1;
-                }
-                this._stashUsed = 0;
-                this._stashByteStart = 0;
-                this._paused = true;
-            }
-        }
-    }, {
-        key: 'resume',
-        value: function resume() {
-            if (this._paused) {
-                this._paused = false;
-                var bytes = this._resumeFrom;
-                this._resumeFrom = 0;
-                this._internalSeek(bytes, true);
-            }
-        }
-    }, {
-        key: 'seek',
-        value: function seek(bytes) {
-            this._paused = false;
-            this._stashUsed = 0;
-            this._stashByteStart = 0;
-            this._internalSeek(bytes, true);
-        }
-
-        /**
-         * When seeking request is from media seeking, unconsumed stash data should be dropped
-         * However, stash data shouldn't be dropped if seeking requested from http reconnection
-         *
-         * @dropUnconsumed: Ignore and discard all unconsumed data in stash buffer
-         */
-
-    }, {
-        key: '_internalSeek',
-        value: function _internalSeek(bytes, dropUnconsumed) {
-            if (this._loader.isWorking()) {
-                this._loader.abort();
-            }
-
-            // dispatch & flush stash buffer before seek
-            this._flushStashBuffer(dropUnconsumed);
-
-            this._loader.destroy();
-            this._loader = null;
-
-            var requestRange = { from: bytes, to: -1 };
-            this._currentRange = { from: requestRange.from, to: -1 };
-
-            this._speedSampler.reset();
-            this._stashSize = this._stashInitialSize;
-            this._createLoader();
-            this._loader.open(this._dataSource, requestRange);
-
-            if (this._onSeeked) {
-                this._onSeeked();
-            }
-        }
-    }, {
-        key: 'updateUrl',
-        value: function updateUrl(url) {
-            if (!url || typeof url !== 'string' || url.length === 0) {
-                throw new _exception.InvalidArgumentException('Url must be a non-empty string!');
-            }
-
-            this._dataSource.url = url;
-
-            // TODO: replace with new url
-        }
-    }, {
-        key: '_expandBuffer',
-        value: function _expandBuffer(expectedBytes) {
-            var bufferNewSize = this._stashSize;
-            while (bufferNewSize + 1024 * 1024 * 1 < expectedBytes) {
-                bufferNewSize *= 2;
-            }
-
-            bufferNewSize += 1024 * 1024 * 1; // bufferSize = stashSize + 1MB
-            if (bufferNewSize === this._bufferSize) {
-                return;
-            }
-
-            var newBuffer = new ArrayBuffer(bufferNewSize);
-
-            if (this._stashUsed > 0) {
-                // copy existing data into new buffer
-                var stashOldArray = new Uint8Array(this._stashBuffer, 0, this._stashUsed);
-                var stashNewArray = new Uint8Array(newBuffer, 0, bufferNewSize);
-                stashNewArray.set(stashOldArray, 0);
-            }
-
-            this._stashBuffer = newBuffer;
-            this._bufferSize = bufferNewSize;
-        }
-    }, {
-        key: '_normalizeSpeed',
-        value: function _normalizeSpeed(input) {
-            var list = this._speedNormalizeList;
-            var last = list.length - 1;
-            var mid = 0;
-            var lbound = 0;
-            var ubound = last;
-
-            if (input < list[0]) {
-                return list[0];
-            }
-
-            // binary search
-            while (lbound <= ubound) {
-                mid = lbound + Math.floor((ubound - lbound) / 2);
-                if (mid === last || input >= list[mid] && input < list[mid + 1]) {
-                    return list[mid];
-                } else if (list[mid] < input) {
-                    lbound = mid + 1;
-                } else {
-                    ubound = mid - 1;
-                }
-            }
-        }
-    }, {
-        key: '_adjustStashSize',
-        value: function _adjustStashSize(normalized) {
-            var stashSizeKB = 0;
-
-            if (this._config.isLive) {
-                // live stream: always use single normalized speed for size of stashSizeKB
-                stashSizeKB = normalized;
-            } else {
-                if (normalized < 512) {
-                    stashSizeKB = normalized;
-                } else if (normalized >= 512 && normalized <= 1024) {
-                    stashSizeKB = Math.floor(normalized * 1.5);
-                } else {
-                    stashSizeKB = normalized * 2;
-                }
-            }
-
-            if (stashSizeKB > 8192) {
-                stashSizeKB = 8192;
-            }
-
-            var bufferSize = stashSizeKB * 1024 + 1024 * 1024 * 1; // stashSize + 1MB
-            if (this._bufferSize < bufferSize) {
-                this._expandBuffer(bufferSize);
-            }
-            this._stashSize = stashSizeKB * 1024;
-        }
-    }, {
-        key: '_dispatchChunks',
-        value: function _dispatchChunks(chunks, byteStart) {
-            this._currentRange.to = byteStart + chunks.byteLength - 1;
-            return this._onDataArrival(chunks, byteStart);
-        }
-    }, {
-        key: '_onURLRedirect',
-        value: function _onURLRedirect(redirectedURL) {
-            this._redirectedURL = redirectedURL;
-            if (this._onRedirect) {
-                this._onRedirect(redirectedURL);
-            }
-        }
-    }, {
-        key: '_onContentLengthKnown',
-        value: function _onContentLengthKnown(contentLength) {
-            if (contentLength && this._fullRequestFlag) {
-                this._totalLength = contentLength;
-                this._fullRequestFlag = false;
-            }
-        }
-    }, {
-        key: '_onLoaderChunkArrival',
-        value: function _onLoaderChunkArrival(chunk, byteStart, receivedLength) {
-            if (!this._onDataArrival) {
-                throw new _exception.IllegalStateException('IOController: No existing consumer (onDataArrival) callback!');
-            }
-            if (this._paused) {
-                return;
-            }
-            if (this._isEarlyEofReconnecting) {
-                // Auto-reconnect for EarlyEof succeed, notify to upper-layer by callback
-                this._isEarlyEofReconnecting = false;
-                if (this._onRecoveredEarlyEof) {
-                    this._onRecoveredEarlyEof();
-                }
-            }
-
-            this._speedSampler.addBytes(chunk.byteLength);
-
-            // adjust stash buffer size according to network speed dynamically
-            var KBps = this._speedSampler.lastSecondKBps;
-            if (KBps !== 0) {
-                var normalized = this._normalizeSpeed(KBps);
-                if (this._speedNormalized !== normalized) {
-                    this._speedNormalized = normalized;
-                    this._adjustStashSize(normalized);
-                }
-            }
-
-            if (!this._enableStash) {
-                // disable stash
-                if (this._stashUsed === 0) {
-                    // dispatch chunk directly to consumer;
-                    // check ret value (consumed bytes) and stash unconsumed to stashBuffer
-                    var consumed = this._dispatchChunks(chunk, byteStart);
-                    if (consumed < chunk.byteLength) {
-                        // unconsumed data remain.
-                        var remain = chunk.byteLength - consumed;
-                        if (remain > this._bufferSize) {
-                            this._expandBuffer(remain);
+                _createClass(IOController, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        if (this._loader.isWorking()) {
+                            this._loader.abort();
                         }
-                        var stashArray = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
-                        stashArray.set(new Uint8Array(chunk, consumed), 0);
-                        this._stashUsed += remain;
-                        this._stashByteStart = byteStart + consumed;
+                        this._loader.destroy();
+                        this._loader = null;
+                        this._loaderClass = null;
+                        this._dataSource = null;
+                        this._stashBuffer = null;
+                        this._stashUsed = this._stashSize = this._bufferSize = this._stashByteStart = 0;
+                        this._currentRange = null;
+                        this._speedSampler = null;
+
+                        this._isEarlyEofReconnecting = false;
+
+                        this._onDataArrival = null;
+                        this._onSeeked = null;
+                        this._onError = null;
+                        this._onComplete = null;
+                        this._onRedirect = null;
+                        this._onRecoveredEarlyEof = null;
+
+                        this._extraData = null;
                     }
-                } else {
-                    // else: Merge chunk into stashBuffer, and dispatch stashBuffer to consumer.
-                    if (this._stashUsed + chunk.byteLength > this._bufferSize) {
-                        this._expandBuffer(this._stashUsed + chunk.byteLength);
+                }, {
+                    key: 'isWorking',
+                    value: function isWorking() {
+                        return this._loader && this._loader.isWorking() && !this._paused;
                     }
-                    var _stashArray = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
-                    _stashArray.set(new Uint8Array(chunk), this._stashUsed);
-                    this._stashUsed += chunk.byteLength;
-                    var _consumed = this._dispatchChunks(this._stashBuffer.slice(0, this._stashUsed), this._stashByteStart);
-                    if (_consumed < this._stashUsed && _consumed > 0) {
-                        // unconsumed data remain
-                        var remainArray = new Uint8Array(this._stashBuffer, _consumed);
-                        _stashArray.set(remainArray, 0);
+                }, {
+                    key: 'isPaused',
+                    value: function isPaused() {
+                        return this._paused;
                     }
-                    this._stashUsed -= _consumed;
-                    this._stashByteStart += _consumed;
-                }
-            } else {
-                // enable stash
-                if (this._stashUsed === 0 && this._stashByteStart === 0) {
-                    // seeked? or init chunk?
-                    // This is the first chunk after seek action
-                    this._stashByteStart = byteStart;
-                }
-                if (this._stashUsed + chunk.byteLength <= this._stashSize) {
-                    // just stash
-                    var _stashArray2 = new Uint8Array(this._stashBuffer, 0, this._stashSize);
-                    _stashArray2.set(new Uint8Array(chunk), this._stashUsed);
-                    this._stashUsed += chunk.byteLength;
-                } else {
-                    // stashUsed + chunkSize > stashSize, size limit exceeded
-                    var _stashArray3 = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
-                    if (this._stashUsed > 0) {
-                        // There're stash datas in buffer
-                        // dispatch the whole stashBuffer, and stash remain data
-                        // then append chunk to stashBuffer (stash)
-                        var buffer = this._stashBuffer.slice(0, this._stashUsed);
-                        var _consumed2 = this._dispatchChunks(buffer, this._stashByteStart);
-                        if (_consumed2 < buffer.byteLength) {
-                            if (_consumed2 > 0) {
-                                var _remainArray = new Uint8Array(buffer, _consumed2);
-                                _stashArray3.set(_remainArray, 0);
-                                this._stashUsed = _remainArray.byteLength;
-                                this._stashByteStart += _consumed2;
+                }, {
+                    key: '_selectSeekHandler',
+                    value: function _selectSeekHandler() {
+                        var config = this._config;
+
+                        if (config.seekType === 'range') {
+                            this._seekHandler = new _rangeSeekHandler2.default(this._config.rangeLoadZeroStart);
+                        } else if (config.seekType === 'param') {
+                            var paramStart = config.seekParamStart || 'bstart';
+                            var paramEnd = config.seekParamEnd || 'bend';
+
+                            this._seekHandler = new _paramSeekHandler2.default(paramStart, paramEnd);
+                        } else if (config.seekType === 'custom') {
+                            if (typeof config.customSeekHandler !== 'function') {
+                                throw new _exception.InvalidArgumentException('Custom seekType specified in config but invalid customSeekHandler!');
+                            }
+                            this._seekHandler = new config.customSeekHandler();
+                        } else {
+                            throw new _exception.InvalidArgumentException('Invalid seekType in config: ' + config.seekType);
+                        }
+                    }
+                }, {
+                    key: '_selectLoader',
+                    value: function _selectLoader() {
+                        if (this._config.customLoader != null) {
+                            this._loaderClass = this._config.customLoader;
+                        } else if (this._isWebSocketURL) {
+                            this._loaderClass = _websocketLoader2.default;
+                        } else if (_fetchStreamLoader2.default.isSupported()) {
+                            this._loaderClass = _fetchStreamLoader2.default;
+                        } else if (_xhrMozChunkedLoader2.default.isSupported()) {
+                            this._loaderClass = _xhrMozChunkedLoader2.default;
+                        } else if (_xhrRangeLoader2.default.isSupported()) {
+                            this._loaderClass = _xhrRangeLoader2.default;
+                        } else {
+                            throw new _exception.RuntimeException('Your browser doesn\'t support xhr with arraybuffer responseType!');
+                        }
+                    }
+                }, {
+                    key: '_createLoader',
+                    value: function _createLoader() {
+                        this._loader = new this._loaderClass(this._seekHandler, this._config);
+                        if (this._loader.needStashBuffer === false) {
+                            this._enableStash = false;
+                        }
+                        this._loader.onContentLengthKnown = this._onContentLengthKnown.bind(this);
+                        this._loader.onURLRedirect = this._onURLRedirect.bind(this);
+                        this._loader.onDataArrival = this._onLoaderChunkArrival.bind(this);
+                        this._loader.onComplete = this._onLoaderComplete.bind(this);
+                        this._loader.onError = this._onLoaderError.bind(this);
+                    }
+                }, {
+                    key: 'open',
+                    value: function open(optionalFrom) {
+                        this._currentRange = { from: 0, to: -1 };
+                        if (optionalFrom) {
+                            this._currentRange.from = optionalFrom;
+                        }
+
+                        this._speedSampler.reset();
+                        if (!optionalFrom) {
+                            this._fullRequestFlag = true;
+                        }
+
+                        this._loader.open(this._dataSource, Object.assign({}, this._currentRange));
+                    }
+                }, {
+                    key: 'abort',
+                    value: function abort() {
+                        this._loader.abort();
+
+                        if (this._paused) {
+                            this._paused = false;
+                            this._resumeFrom = 0;
+                        }
+                    }
+                }, {
+                    key: 'pause',
+                    value: function pause() {
+                        if (this.isWorking()) {
+                            this._loader.abort();
+
+                            if (this._stashUsed !== 0) {
+                                this._resumeFrom = this._stashByteStart;
+                                this._currentRange.to = this._stashByteStart - 1;
+                            } else {
+                                this._resumeFrom = this._currentRange.to + 1;
+                            }
+                            this._stashUsed = 0;
+                            this._stashByteStart = 0;
+                            this._paused = true;
+                        }
+                    }
+                }, {
+                    key: 'resume',
+                    value: function resume() {
+                        if (this._paused) {
+                            this._paused = false;
+                            var bytes = this._resumeFrom;
+                            this._resumeFrom = 0;
+                            this._internalSeek(bytes, true);
+                        }
+                    }
+                }, {
+                    key: 'seek',
+                    value: function seek(bytes) {
+                        this._paused = false;
+                        this._stashUsed = 0;
+                        this._stashByteStart = 0;
+                        this._internalSeek(bytes, true);
+                    }
+
+                    /**
+                     * When seeking request is from media seeking, unconsumed stash data should be dropped
+                     * However, stash data shouldn't be dropped if seeking requested from http reconnection
+                     *
+                     * @dropUnconsumed: Ignore and discard all unconsumed data in stash buffer
+                     */
+
+                }, {
+                    key: '_internalSeek',
+                    value: function _internalSeek(bytes, dropUnconsumed) {
+                        if (this._loader.isWorking()) {
+                            this._loader.abort();
+                        }
+
+                        // dispatch & flush stash buffer before seek
+                        this._flushStashBuffer(dropUnconsumed);
+
+                        this._loader.destroy();
+                        this._loader = null;
+
+                        var requestRange = { from: bytes, to: -1 };
+                        this._currentRange = { from: requestRange.from, to: -1 };
+
+                        this._speedSampler.reset();
+                        this._stashSize = this._stashInitialSize;
+                        this._createLoader();
+                        this._loader.open(this._dataSource, requestRange);
+
+                        if (this._onSeeked) {
+                            this._onSeeked();
+                        }
+                    }
+                }, {
+                    key: 'updateUrl',
+                    value: function updateUrl(url) {
+                        if (!url || typeof url !== 'string' || url.length === 0) {
+                            throw new _exception.InvalidArgumentException('Url must be a non-empty string!');
+                        }
+
+                        this._dataSource.url = url;
+
+                        // TODO: replace with new url
+                    }
+                }, {
+                    key: '_expandBuffer',
+                    value: function _expandBuffer(expectedBytes) {
+                        var bufferNewSize = this._stashSize;
+                        while (bufferNewSize + 1024 * 1024 * 1 < expectedBytes) {
+                            bufferNewSize *= 2;
+                        }
+
+                        bufferNewSize += 1024 * 1024 * 1; // bufferSize = stashSize + 1MB
+                        if (bufferNewSize === this._bufferSize) {
+                            return;
+                        }
+
+                        var newBuffer = new ArrayBuffer(bufferNewSize);
+
+                        if (this._stashUsed > 0) {
+                            // copy existing data into new buffer
+                            var stashOldArray = new Uint8Array(this._stashBuffer, 0, this._stashUsed);
+                            var stashNewArray = new Uint8Array(newBuffer, 0, bufferNewSize);
+                            stashNewArray.set(stashOldArray, 0);
+                        }
+
+                        this._stashBuffer = newBuffer;
+                        this._bufferSize = bufferNewSize;
+                    }
+                }, {
+                    key: '_normalizeSpeed',
+                    value: function _normalizeSpeed(input) {
+                        var list = this._speedNormalizeList;
+                        var last = list.length - 1;
+                        var mid = 0;
+                        var lbound = 0;
+                        var ubound = last;
+
+                        if (input < list[0]) {
+                            return list[0];
+                        }
+
+                        // binary search
+                        while (lbound <= ubound) {
+                            mid = lbound + Math.floor((ubound - lbound) / 2);
+                            if (mid === last || input >= list[mid] && input < list[mid + 1]) {
+                                return list[mid];
+                            } else if (list[mid] < input) {
+                                lbound = mid + 1;
+                            } else {
+                                ubound = mid - 1;
+                            }
+                        }
+                    }
+                }, {
+                    key: '_adjustStashSize',
+                    value: function _adjustStashSize(normalized) {
+                        var stashSizeKB = 0;
+
+                        if (this._config.isLive) {
+                            // live stream: always use single normalized speed for size of stashSizeKB
+                            stashSizeKB = normalized;
+                        } else {
+                            if (normalized < 512) {
+                                stashSizeKB = normalized;
+                            } else if (normalized >= 512 && normalized <= 1024) {
+                                stashSizeKB = Math.floor(normalized * 1.5);
+                            } else {
+                                stashSizeKB = normalized * 2;
+                            }
+                        }
+
+                        if (stashSizeKB > 8192) {
+                            stashSizeKB = 8192;
+                        }
+
+                        var bufferSize = stashSizeKB * 1024 + 1024 * 1024 * 1; // stashSize + 1MB
+                        if (this._bufferSize < bufferSize) {
+                            this._expandBuffer(bufferSize);
+                        }
+                        this._stashSize = stashSizeKB * 1024;
+                    }
+                }, {
+                    key: '_dispatchChunks',
+                    value: function _dispatchChunks(chunks, byteStart) {
+                        this._currentRange.to = byteStart + chunks.byteLength - 1;
+                        return this._onDataArrival(chunks, byteStart);
+                    }
+                }, {
+                    key: '_onURLRedirect',
+                    value: function _onURLRedirect(redirectedURL) {
+                        this._redirectedURL = redirectedURL;
+                        if (this._onRedirect) {
+                            this._onRedirect(redirectedURL);
+                        }
+                    }
+                }, {
+                    key: '_onContentLengthKnown',
+                    value: function _onContentLengthKnown(contentLength) {
+                        if (contentLength && this._fullRequestFlag) {
+                            this._totalLength = contentLength;
+                            this._fullRequestFlag = false;
+                        }
+                    }
+                }, {
+                    key: '_onLoaderChunkArrival',
+                    value: function _onLoaderChunkArrival(chunk, byteStart, receivedLength) {
+                        if (!this._onDataArrival) {
+                            throw new _exception.IllegalStateException('IOController: No existing consumer (onDataArrival) callback!');
+                        }
+                        if (this._paused) {
+                            return;
+                        }
+                        if (this._isEarlyEofReconnecting) {
+                            // Auto-reconnect for EarlyEof succeed, notify to upper-layer by callback
+                            this._isEarlyEofReconnecting = false;
+                            if (this._onRecoveredEarlyEof) {
+                                this._onRecoveredEarlyEof();
+                            }
+                        }
+
+                        this._speedSampler.addBytes(chunk.byteLength);
+
+                        // adjust stash buffer size according to network speed dynamically
+                        var KBps = this._speedSampler.lastSecondKBps;
+                        if (KBps !== 0) {
+                            var normalized = this._normalizeSpeed(KBps);
+                            if (this._speedNormalized !== normalized) {
+                                this._speedNormalized = normalized;
+                                this._adjustStashSize(normalized);
+                            }
+                        }
+
+                        if (!this._enableStash) {
+                            // disable stash
+                            if (this._stashUsed === 0) {
+                                // dispatch chunk directly to consumer;
+                                // check ret value (consumed bytes) and stash unconsumed to stashBuffer
+                                var consumed = this._dispatchChunks(chunk, byteStart);
+                                if (consumed < chunk.byteLength) {
+                                    // unconsumed data remain.
+                                    var remain = chunk.byteLength - consumed;
+                                    if (remain > this._bufferSize) {
+                                        this._expandBuffer(remain);
+                                    }
+                                    var stashArray = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
+                                    stashArray.set(new Uint8Array(chunk, consumed), 0);
+                                    this._stashUsed += remain;
+                                    this._stashByteStart = byteStart + consumed;
+                                }
+                            } else {
+                                // else: Merge chunk into stashBuffer, and dispatch stashBuffer to consumer.
+                                if (this._stashUsed + chunk.byteLength > this._bufferSize) {
+                                    this._expandBuffer(this._stashUsed + chunk.byteLength);
+                                }
+                                var _stashArray = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
+                                _stashArray.set(new Uint8Array(chunk), this._stashUsed);
+                                this._stashUsed += chunk.byteLength;
+                                var _consumed = this._dispatchChunks(this._stashBuffer.slice(0, this._stashUsed), this._stashByteStart);
+                                if (_consumed < this._stashUsed && _consumed > 0) {
+                                    // unconsumed data remain
+                                    var remainArray = new Uint8Array(this._stashBuffer, _consumed);
+                                    _stashArray.set(remainArray, 0);
+                                }
+                                this._stashUsed -= _consumed;
+                                this._stashByteStart += _consumed;
                             }
                         } else {
-                            this._stashUsed = 0;
-                            this._stashByteStart += _consumed2;
-                        }
-                        if (this._stashUsed + chunk.byteLength > this._bufferSize) {
-                            this._expandBuffer(this._stashUsed + chunk.byteLength);
-                            _stashArray3 = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
-                        }
-                        _stashArray3.set(new Uint8Array(chunk), this._stashUsed);
-                        this._stashUsed += chunk.byteLength;
-                    } else {
-                        // stash buffer empty, but chunkSize > stashSize (oh, holy shit)
-                        // dispatch chunk directly and stash remain data
-                        var _consumed3 = this._dispatchChunks(chunk, byteStart);
-                        if (_consumed3 < chunk.byteLength) {
-                            var _remain = chunk.byteLength - _consumed3;
-                            if (_remain > this._bufferSize) {
-                                this._expandBuffer(_remain);
-                                _stashArray3 = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
+                            // enable stash
+                            if (this._stashUsed === 0 && this._stashByteStart === 0) {
+                                // seeked? or init chunk?
+                                // This is the first chunk after seek action
+                                this._stashByteStart = byteStart;
                             }
-                            _stashArray3.set(new Uint8Array(chunk, _consumed3), 0);
-                            this._stashUsed += _remain;
-                            this._stashByteStart = byteStart + _consumed3;
+                            if (this._stashUsed + chunk.byteLength <= this._stashSize) {
+                                // just stash
+                                var _stashArray2 = new Uint8Array(this._stashBuffer, 0, this._stashSize);
+                                _stashArray2.set(new Uint8Array(chunk), this._stashUsed);
+                                this._stashUsed += chunk.byteLength;
+                            } else {
+                                // stashUsed + chunkSize > stashSize, size limit exceeded
+                                var _stashArray3 = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
+                                if (this._stashUsed > 0) {
+                                    // There're stash datas in buffer
+                                    // dispatch the whole stashBuffer, and stash remain data
+                                    // then append chunk to stashBuffer (stash)
+                                    var buffer = this._stashBuffer.slice(0, this._stashUsed);
+                                    var _consumed2 = this._dispatchChunks(buffer, this._stashByteStart);
+                                    if (_consumed2 < buffer.byteLength) {
+                                        if (_consumed2 > 0) {
+                                            var _remainArray = new Uint8Array(buffer, _consumed2);
+                                            _stashArray3.set(_remainArray, 0);
+                                            this._stashUsed = _remainArray.byteLength;
+                                            this._stashByteStart += _consumed2;
+                                        }
+                                    } else {
+                                        this._stashUsed = 0;
+                                        this._stashByteStart += _consumed2;
+                                    }
+                                    if (this._stashUsed + chunk.byteLength > this._bufferSize) {
+                                        this._expandBuffer(this._stashUsed + chunk.byteLength);
+                                        _stashArray3 = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
+                                    }
+                                    _stashArray3.set(new Uint8Array(chunk), this._stashUsed);
+                                    this._stashUsed += chunk.byteLength;
+                                } else {
+                                    // stash buffer empty, but chunkSize > stashSize (oh, holy shit)
+                                    // dispatch chunk directly and stash remain data
+                                    var _consumed3 = this._dispatchChunks(chunk, byteStart);
+                                    if (_consumed3 < chunk.byteLength) {
+                                        var _remain = chunk.byteLength - _consumed3;
+                                        if (_remain > this._bufferSize) {
+                                            this._expandBuffer(_remain);
+                                            _stashArray3 = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
+                                        }
+                                        _stashArray3.set(new Uint8Array(chunk, _consumed3), 0);
+                                        this._stashUsed += _remain;
+                                        this._stashByteStart = byteStart + _consumed3;
+                                    }
+                                }
+                            }
                         }
                     }
-                }
-            }
-        }
-    }, {
-        key: '_flushStashBuffer',
-        value: function _flushStashBuffer(dropUnconsumed) {
-            if (this._stashUsed > 0) {
-                var buffer = this._stashBuffer.slice(0, this._stashUsed);
-                var consumed = this._dispatchChunks(buffer, this._stashByteStart);
-                var remain = buffer.byteLength - consumed;
+                }, {
+                    key: '_flushStashBuffer',
+                    value: function _flushStashBuffer(dropUnconsumed) {
+                        if (this._stashUsed > 0) {
+                            var buffer = this._stashBuffer.slice(0, this._stashUsed);
+                            var consumed = this._dispatchChunks(buffer, this._stashByteStart);
+                            var remain = buffer.byteLength - consumed;
 
-                if (consumed < buffer.byteLength) {
-                    if (dropUnconsumed) {
-                        _logger2.default.w(this.TAG, remain + ' bytes unconsumed data remain when flush buffer, dropped');
-                    } else {
-                        if (consumed > 0) {
-                            var stashArray = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
-                            var remainArray = new Uint8Array(buffer, consumed);
-                            stashArray.set(remainArray, 0);
-                            this._stashUsed = remainArray.byteLength;
-                            this._stashByteStart += consumed;
+                            if (consumed < buffer.byteLength) {
+                                if (dropUnconsumed) {
+                                    _logger2.default.w(this.TAG, remain + ' bytes unconsumed data remain when flush buffer, dropped');
+                                } else {
+                                    if (consumed > 0) {
+                                        var stashArray = new Uint8Array(this._stashBuffer, 0, this._bufferSize);
+                                        var remainArray = new Uint8Array(buffer, consumed);
+                                        stashArray.set(remainArray, 0);
+                                        this._stashUsed = remainArray.byteLength;
+                                        this._stashByteStart += consumed;
+                                    }
+                                    return 0;
+                                }
+                            }
+                            this._stashUsed = 0;
+                            this._stashByteStart = 0;
+                            return remain;
                         }
                         return 0;
                     }
-                }
-                this._stashUsed = 0;
-                this._stashByteStart = 0;
-                return remain;
-            }
-            return 0;
-        }
-    }, {
-        key: '_onLoaderComplete',
-        value: function _onLoaderComplete(from, to) {
-            // Force-flush stash buffer, and drop unconsumed data
-            this._flushStashBuffer(true);
+                }, {
+                    key: '_onLoaderComplete',
+                    value: function _onLoaderComplete(from, to) {
+                        // Force-flush stash buffer, and drop unconsumed data
+                        this._flushStashBuffer(true);
 
-            if (this._onComplete) {
-                this._onComplete(this._extraData);
-            }
-        }
-    }, {
-        key: '_onLoaderError',
-        value: function _onLoaderError(type, data) {
-            _logger2.default.e(this.TAG, 'Loader error, code = ' + data.code + ', msg = ' + data.msg);
-
-            this._flushStashBuffer(false);
-
-            if (this._isEarlyEofReconnecting) {
-                // Auto-reconnect for EarlyEof failed, throw UnrecoverableEarlyEof error to upper-layer
-                this._isEarlyEofReconnecting = false;
-                type = _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF;
-            }
-
-            switch (type) {
-                case _loader.LoaderErrors.EARLY_EOF:
-                    {
-                        if (!this._config.isLive) {
-                            // Do internal http reconnect if not live stream
-                            if (this._totalLength) {
-                                var nextFrom = this._currentRange.to + 1;
-                                if (nextFrom < this._totalLength) {
-                                    _logger2.default.w(this.TAG, 'Connection lost, trying reconnect...');
-                                    this._isEarlyEofReconnecting = true;
-                                    this._internalSeek(nextFrom, false);
-                                }
-                                return;
-                            }
-                            // else: We don't know totalLength, throw UnrecoverableEarlyEof
+                        if (this._onComplete) {
+                            this._onComplete(this._extraData);
                         }
-                        // live stream: throw UnrecoverableEarlyEof error to upper-layer
-                        type = _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF;
-                        break;
                     }
-                case _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF:
-                case _loader.LoaderErrors.CONNECTING_TIMEOUT:
-                case _loader.LoaderErrors.HTTP_STATUS_CODE_INVALID:
-                case _loader.LoaderErrors.EXCEPTION:
-                    break;
-            }
+                }, {
+                    key: '_onLoaderError',
+                    value: function _onLoaderError(type, data) {
+                        _logger2.default.e(this.TAG, 'Loader error, code = ' + data.code + ', msg = ' + data.msg);
 
-            if (this._onError) {
-                this._onError(type, data);
-            } else {
-                throw new _exception.RuntimeException('IOException: ' + data.msg);
-            }
-        }
-    }, {
-        key: 'status',
-        get: function get() {
-            return this._loader.status;
-        }
-    }, {
-        key: 'extraData',
-        get: function get() {
-            return this._extraData;
-        },
-        set: function set(data) {
-            this._extraData = data;
-        }
+                        this._flushStashBuffer(false);
 
-        // prototype: function onDataArrival(chunks: ArrayBuffer, byteStart: number): number
+                        if (this._isEarlyEofReconnecting) {
+                            // Auto-reconnect for EarlyEof failed, throw UnrecoverableEarlyEof error to upper-layer
+                            this._isEarlyEofReconnecting = false;
+                            type = _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF;
+                        }
 
-    }, {
-        key: 'onDataArrival',
-        get: function get() {
-            return this._onDataArrival;
-        },
-        set: function set(callback) {
-            this._onDataArrival = callback;
-        }
-    }, {
-        key: 'onSeeked',
-        get: function get() {
-            return this._onSeeked;
-        },
-        set: function set(callback) {
-            this._onSeeked = callback;
-        }
+                        switch (type) {
+                            case _loader.LoaderErrors.EARLY_EOF:
+                                {
+                                    if (!this._config.isLive) {
+                                        // Do internal http reconnect if not live stream
+                                        if (this._totalLength) {
+                                            var nextFrom = this._currentRange.to + 1;
+                                            if (nextFrom < this._totalLength) {
+                                                _logger2.default.w(this.TAG, 'Connection lost, trying reconnect...');
+                                                this._isEarlyEofReconnecting = true;
+                                                this._internalSeek(nextFrom, false);
+                                            }
+                                            return;
+                                        }
+                                        // else: We don't know totalLength, throw UnrecoverableEarlyEof
+                                    }
+                                    // live stream: throw UnrecoverableEarlyEof error to upper-layer
+                                    type = _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF;
+                                    break;
+                                }
+                            case _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF:
+                            case _loader.LoaderErrors.CONNECTING_TIMEOUT:
+                            case _loader.LoaderErrors.HTTP_STATUS_CODE_INVALID:
+                            case _loader.LoaderErrors.EXCEPTION:
+                                break;
+                        }
 
-        // prototype: function onError(type: number, info: {code: number, msg: string}): void
+                        if (this._onError) {
+                            this._onError(type, data);
+                        } else {
+                            throw new _exception.RuntimeException('IOException: ' + data.msg);
+                        }
+                    }
+                }, {
+                    key: 'status',
+                    get: function get() {
+                        return this._loader.status;
+                    }
+                }, {
+                    key: 'extraData',
+                    get: function get() {
+                        return this._extraData;
+                    },
+                    set: function set(data) {
+                        this._extraData = data;
+                    }
 
-    }, {
-        key: 'onError',
-        get: function get() {
-            return this._onError;
-        },
-        set: function set(callback) {
-            this._onError = callback;
-        }
-    }, {
-        key: 'onComplete',
-        get: function get() {
-            return this._onComplete;
-        },
-        set: function set(callback) {
-            this._onComplete = callback;
-        }
-    }, {
-        key: 'onRedirect',
-        get: function get() {
-            return this._onRedirect;
-        },
-        set: function set(callback) {
-            this._onRedirect = callback;
-        }
-    }, {
-        key: 'onRecoveredEarlyEof',
-        get: function get() {
-            return this._onRecoveredEarlyEof;
-        },
-        set: function set(callback) {
-            this._onRecoveredEarlyEof = callback;
-        }
-    }, {
-        key: 'currentURL',
-        get: function get() {
-            return this._dataSource.url;
-        }
-    }, {
-        key: 'hasRedirect',
-        get: function get() {
-            return this._redirectedURL != null || this._dataSource.redirectedURL != undefined;
-        }
-    }, {
-        key: 'currentRedirectedURL',
-        get: function get() {
-            return this._redirectedURL || this._dataSource.redirectedURL;
-        }
+                    // prototype: function onDataArrival(chunks: ArrayBuffer, byteStart: number): number
 
-        // in KB/s
+                }, {
+                    key: 'onDataArrival',
+                    get: function get() {
+                        return this._onDataArrival;
+                    },
+                    set: function set(callback) {
+                        this._onDataArrival = callback;
+                    }
+                }, {
+                    key: 'onSeeked',
+                    get: function get() {
+                        return this._onSeeked;
+                    },
+                    set: function set(callback) {
+                        this._onSeeked = callback;
+                    }
 
-    }, {
-        key: 'currentSpeed',
-        get: function get() {
-            if (this._loaderClass === _xhrRangeLoader2.default) {
-                // SpeedSampler is inaccuracy if loader is RangeLoader
-                return this._loader.currentSpeed;
-            }
-            return this._speedSampler.lastSecondKBps;
-        }
-    }, {
-        key: 'loaderType',
-        get: function get() {
-            return this._loader.type;
-        }
-    }]);
+                    // prototype: function onError(type: number, info: {code: number, msg: string}): void
 
-    return IOController;
-}();
+                }, {
+                    key: 'onError',
+                    get: function get() {
+                        return this._onError;
+                    },
+                    set: function set(callback) {
+                        this._onError = callback;
+                    }
+                }, {
+                    key: 'onComplete',
+                    get: function get() {
+                        return this._onComplete;
+                    },
+                    set: function set(callback) {
+                        this._onComplete = callback;
+                    }
+                }, {
+                    key: 'onRedirect',
+                    get: function get() {
+                        return this._onRedirect;
+                    },
+                    set: function set(callback) {
+                        this._onRedirect = callback;
+                    }
+                }, {
+                    key: 'onRecoveredEarlyEof',
+                    get: function get() {
+                        return this._onRecoveredEarlyEof;
+                    },
+                    set: function set(callback) {
+                        this._onRecoveredEarlyEof = callback;
+                    }
+                }, {
+                    key: 'currentURL',
+                    get: function get() {
+                        return this._dataSource.url;
+                    }
+                }, {
+                    key: 'hasRedirect',
+                    get: function get() {
+                        return this._redirectedURL != null || this._dataSource.redirectedURL != undefined;
+                    }
+                }, {
+                    key: 'currentRedirectedURL',
+                    get: function get() {
+                        return this._redirectedURL || this._dataSource.redirectedURL;
+                    }
 
-exports.default = IOController;
+                    // in KB/s
 
-},{"../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){
-'use strict';
+                }, {
+                    key: 'currentSpeed',
+                    get: function get() {
+                        if (this._loaderClass === _xhrRangeLoader2.default) {
+                            // SpeedSampler is inaccuracy if loader is RangeLoader
+                            return this._loader.currentSpeed;
+                        }
+                        return this._speedSampler.lastSecondKBps;
+                    }
+                }, {
+                    key: 'loaderType',
+                    get: function get() {
+                        return this._loader.type;
+                    }
+                }]);
 
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-exports.BaseLoader = exports.LoaderErrors = exports.LoaderStatus = undefined;
+                return IOController;
+            }();
 
-var _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; }; }(); /*
+            exports.default = IOController;
+
+        }, { "../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) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+            exports.BaseLoader = exports.LoaderErrors = exports.LoaderStatus = undefined;
+
+            var _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; }; }(); /*
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * Copyright (C) 2016 Bilibili. All Rights Reserved.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       *
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * @author zheng qian <xqq@xqq.im>
@@ -7210,1661 +7221,1661 @@
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * limitations under the License.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       */
 
-var _exception = _dereq_('../utils/exception.js');
+            var _exception = _dereq_('../utils/exception.js');
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var LoaderStatus = exports.LoaderStatus = {
-    kIdle: 0,
-    kConnecting: 1,
-    kBuffering: 2,
-    kError: 3,
-    kComplete: 4
-};
-
-var LoaderErrors = exports.LoaderErrors = {
-    OK: 'OK',
-    EXCEPTION: 'Exception',
-    HTTP_STATUS_CODE_INVALID: 'HttpStatusCodeInvalid',
-    CONNECTING_TIMEOUT: 'ConnectingTimeout',
-    EARLY_EOF: 'EarlyEof',
-    UNRECOVERABLE_EARLY_EOF: 'UnrecoverableEarlyEof'
-};
-
-/* Loader has callbacks which have following prototypes:
- *     function onContentLengthKnown(contentLength: number): void
- *     function onURLRedirect(url: string): void
- *     function onDataArrival(chunk: ArrayBuffer, byteStart: number, receivedLength: number): void
- *     function onError(errorType: number, errorInfo: {code: number, msg: string}): void
- *     function onComplete(rangeFrom: number, rangeTo: number): void
- */
-
-var BaseLoader = exports.BaseLoader = function () {
-    function BaseLoader(typeName) {
-        _classCallCheck(this, BaseLoader);
-
-        this._type = typeName || 'undefined';
-        this._status = LoaderStatus.kIdle;
-        this._needStash = false;
-        // callbacks
-        this._onContentLengthKnown = null;
-        this._onURLRedirect = null;
-        this._onDataArrival = null;
-        this._onError = null;
-        this._onComplete = null;
-    }
-
-    _createClass(BaseLoader, [{
-        key: 'destroy',
-        value: function destroy() {
-            this._status = LoaderStatus.kIdle;
-            this._onContentLengthKnown = null;
-            this._onURLRedirect = null;
-            this._onDataArrival = null;
-            this._onError = null;
-            this._onComplete = null;
-        }
-    }, {
-        key: 'isWorking',
-        value: function isWorking() {
-            return this._status === LoaderStatus.kConnecting || this._status === LoaderStatus.kBuffering;
-        }
-    }, {
-        key: 'open',
-
-
-        // pure virtual
-        value: function open(dataSource, range) {
-            throw new _exception.NotImplementedException('Unimplemented abstract function!');
-        }
-    }, {
-        key: 'abort',
-        value: function abort() {
-            throw new _exception.NotImplementedException('Unimplemented abstract function!');
-        }
-    }, {
-        key: 'type',
-        get: function get() {
-            return this._type;
-        }
-    }, {
-        key: 'status',
-        get: function get() {
-            return this._status;
-        }
-    }, {
-        key: 'needStashBuffer',
-        get: function get() {
-            return this._needStash;
-        }
-    }, {
-        key: 'onContentLengthKnown',
-        get: function get() {
-            return this._onContentLengthKnown;
-        },
-        set: function set(callback) {
-            this._onContentLengthKnown = callback;
-        }
-    }, {
-        key: 'onURLRedirect',
-        get: function get() {
-            return this._onURLRedirect;
-        },
-        set: function set(callback) {
-            this._onURLRedirect = callback;
-        }
-    }, {
-        key: 'onDataArrival',
-        get: function get() {
-            return this._onDataArrival;
-        },
-        set: function set(callback) {
-            this._onDataArrival = callback;
-        }
-    }, {
-        key: 'onError',
-        get: function get() {
-            return this._onError;
-        },
-        set: function set(callback) {
-            this._onError = callback;
-        }
-    }, {
-        key: 'onComplete',
-        get: function get() {
-            return this._onComplete;
-        },
-        set: function set(callback) {
-            this._onComplete = callback;
-        }
-    }]);
-
-    return BaseLoader;
-}();
-
-},{"../utils/exception.js":40}],25:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var ParamSeekHandler = function () {
-    function ParamSeekHandler(paramStart, paramEnd) {
-        _classCallCheck(this, ParamSeekHandler);
-
-        this._startName = paramStart;
-        this._endName = paramEnd;
-    }
-
-    _createClass(ParamSeekHandler, [{
-        key: 'getConfig',
-        value: function getConfig(baseUrl, range) {
-            var url = baseUrl;
-
-            if (range.from !== 0 || range.to !== -1) {
-                var needAnd = true;
-                if (url.indexOf('?') === -1) {
-                    url += '?';
-                    needAnd = false;
-                }
-
-                if (needAnd) {
-                    url += '&';
-                }
-
-                url += this._startName + '=' + range.from.toString();
-
-                if (range.to !== -1) {
-                    url += '&' + this._endName + '=' + range.to.toString();
-                }
-            }
-
-            return {
-                url: url,
-                headers: {}
+            var LoaderStatus = exports.LoaderStatus = {
+                kIdle: 0,
+                kConnecting: 1,
+                kBuffering: 2,
+                kError: 3,
+                kComplete: 4
             };
-        }
-    }, {
-        key: 'removeURLParameters',
-        value: function removeURLParameters(seekedURL) {
-            var baseURL = seekedURL.split('?')[0];
-            var params = undefined;
 
-            var queryIndex = seekedURL.indexOf('?');
-            if (queryIndex !== -1) {
-                params = seekedURL.substring(queryIndex + 1);
-            }
+            var LoaderErrors = exports.LoaderErrors = {
+                OK: 'OK',
+                EXCEPTION: 'Exception',
+                HTTP_STATUS_CODE_INVALID: 'HttpStatusCodeInvalid',
+                CONNECTING_TIMEOUT: 'ConnectingTimeout',
+                EARLY_EOF: 'EarlyEof',
+                UNRECOVERABLE_EARLY_EOF: 'UnrecoverableEarlyEof'
+            };
 
-            var resultParams = '';
+            /* Loader has callbacks which have following prototypes:
+             *     function onContentLengthKnown(contentLength: number): void
+             *     function onURLRedirect(url: string): void
+             *     function onDataArrival(chunk: ArrayBuffer, byteStart: number, receivedLength: number): void
+             *     function onError(errorType: number, errorInfo: {code: number, msg: string}): void
+             *     function onComplete(rangeFrom: number, rangeTo: number): void
+             */
 
-            if (params != undefined && params.length > 0) {
-                var pairs = params.split('&');
+            var BaseLoader = exports.BaseLoader = function () {
+                function BaseLoader(typeName) {
+                    _classCallCheck(this, BaseLoader);
 
-                for (var i = 0; i < pairs.length; i++) {
-                    var pair = pairs[i].split('=');
-                    var requireAnd = i > 0;
+                    this._type = typeName || 'undefined';
+                    this._status = LoaderStatus.kIdle;
+                    this._needStash = false;
+                    // callbacks
+                    this._onContentLengthKnown = null;
+                    this._onURLRedirect = null;
+                    this._onDataArrival = null;
+                    this._onError = null;
+                    this._onComplete = null;
+                }
 
-                    if (pair[0] !== this._startName && pair[0] !== this._endName) {
-                        if (requireAnd) {
-                            resultParams += '&';
+                _createClass(BaseLoader, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        this._status = LoaderStatus.kIdle;
+                        this._onContentLengthKnown = null;
+                        this._onURLRedirect = null;
+                        this._onDataArrival = null;
+                        this._onError = null;
+                        this._onComplete = null;
+                    }
+                }, {
+                    key: 'isWorking',
+                    value: function isWorking() {
+                        return this._status === LoaderStatus.kConnecting || this._status === LoaderStatus.kBuffering;
+                    }
+                }, {
+                    key: 'open',
+
+
+                    // pure virtual
+                    value: function open(dataSource, range) {
+                        throw new _exception.NotImplementedException('Unimplemented abstract function!');
+                    }
+                }, {
+                    key: 'abort',
+                    value: function abort() {
+                        throw new _exception.NotImplementedException('Unimplemented abstract function!');
+                    }
+                }, {
+                    key: 'type',
+                    get: function get() {
+                        return this._type;
+                    }
+                }, {
+                    key: 'status',
+                    get: function get() {
+                        return this._status;
+                    }
+                }, {
+                    key: 'needStashBuffer',
+                    get: function get() {
+                        return this._needStash;
+                    }
+                }, {
+                    key: 'onContentLengthKnown',
+                    get: function get() {
+                        return this._onContentLengthKnown;
+                    },
+                    set: function set(callback) {
+                        this._onContentLengthKnown = callback;
+                    }
+                }, {
+                    key: 'onURLRedirect',
+                    get: function get() {
+                        return this._onURLRedirect;
+                    },
+                    set: function set(callback) {
+                        this._onURLRedirect = callback;
+                    }
+                }, {
+                    key: 'onDataArrival',
+                    get: function get() {
+                        return this._onDataArrival;
+                    },
+                    set: function set(callback) {
+                        this._onDataArrival = callback;
+                    }
+                }, {
+                    key: 'onError',
+                    get: function get() {
+                        return this._onError;
+                    },
+                    set: function set(callback) {
+                        this._onError = callback;
+                    }
+                }, {
+                    key: 'onComplete',
+                    get: function get() {
+                        return this._onComplete;
+                    },
+                    set: function set(callback) {
+                        this._onComplete = callback;
+                    }
+                }]);
+
+                return BaseLoader;
+            }();
+
+        }, { "../utils/exception.js": 40 }], 25: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }();
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var ParamSeekHandler = function () {
+                function ParamSeekHandler(paramStart, paramEnd) {
+                    _classCallCheck(this, ParamSeekHandler);
+
+                    this._startName = paramStart;
+                    this._endName = paramEnd;
+                }
+
+                _createClass(ParamSeekHandler, [{
+                    key: 'getConfig',
+                    value: function getConfig(baseUrl, range) {
+                        var url = baseUrl;
+
+                        if (range.from !== 0 || range.to !== -1) {
+                            var needAnd = true;
+                            if (url.indexOf('?') === -1) {
+                                url += '?';
+                                needAnd = false;
+                            }
+
+                            if (needAnd) {
+                                url += '&';
+                            }
+
+                            url += this._startName + '=' + range.from.toString();
+
+                            if (range.to !== -1) {
+                                url += '&' + this._endName + '=' + range.to.toString();
+                            }
                         }
-                        resultParams += pairs[i];
+
+                        return {
+                            url: url,
+                            headers: {}
+                        };
                     }
-                }
-            }
+                }, {
+                    key: 'removeURLParameters',
+                    value: function removeURLParameters(seekedURL) {
+                        var baseURL = seekedURL.split('?')[0];
+                        var params = undefined;
 
-            return resultParams.length === 0 ? baseURL : baseURL + '?' + resultParams;
-        }
-    }]);
+                        var queryIndex = seekedURL.indexOf('?');
+                        if (queryIndex !== -1) {
+                            params = seekedURL.substring(queryIndex + 1);
+                        }
 
-    return ParamSeekHandler;
-}();
+                        var resultParams = '';
 
-exports.default = ParamSeekHandler;
+                        if (params != undefined && params.length > 0) {
+                            var pairs = params.split('&');
 
-},{}],26:[function(_dereq_,module,exports){
-'use strict';
+                            for (var i = 0; i < pairs.length; i++) {
+                                var pair = pairs[i].split('=');
+                                var requireAnd = i > 0;
 
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
+                                if (pair[0] !== this._startName && pair[0] !== this._endName) {
+                                    if (requireAnd) {
+                                        resultParams += '&';
+                                    }
+                                    resultParams += pairs[i];
+                                }
+                            }
+                        }
 
-var _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; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var RangeSeekHandler = function () {
-    function RangeSeekHandler(zeroStart) {
-        _classCallCheck(this, RangeSeekHandler);
-
-        this._zeroStart = zeroStart || false;
-    }
-
-    _createClass(RangeSeekHandler, [{
-        key: 'getConfig',
-        value: function getConfig(url, range) {
-            var headers = {};
-
-            if (range.from !== 0 || range.to !== -1) {
-                var param = void 0;
-                if (range.to !== -1) {
-                    param = 'bytes=' + range.from.toString() + '-' + range.to.toString();
-                } else {
-                    param = 'bytes=' + range.from.toString() + '-';
-                }
-                headers['Range'] = param;
-            } else if (this._zeroStart) {
-                headers['Range'] = 'bytes=0-';
-            }
-
-            return {
-                url: url,
-                headers: headers
-            };
-        }
-    }, {
-        key: 'removeURLParameters',
-        value: function removeURLParameters(seekedURL) {
-            return seekedURL;
-        }
-    }]);
-
-    return RangeSeekHandler;
-}();
-
-exports.default = RangeSeekHandler;
-
-},{}],27:[function(_dereq_,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Utility class to calculate realtime network I/O speed
-var SpeedSampler = function () {
-    function SpeedSampler() {
-        _classCallCheck(this, SpeedSampler);
-
-        // milliseconds
-        this._firstCheckpoint = 0;
-        this._lastCheckpoint = 0;
-        this._intervalBytes = 0;
-        this._totalBytes = 0;
-        this._lastSecondBytes = 0;
-
-        // compatibility detection
-        if (self.performance && self.performance.now) {
-            this._now = self.performance.now.bind(self.performance);
-        } else {
-            this._now = Date.now;
-        }
-    }
-
-    _createClass(SpeedSampler, [{
-        key: "reset",
-        value: function reset() {
-            this._firstCheckpoint = this._lastCheckpoint = 0;
-            this._totalBytes = this._intervalBytes = 0;
-            this._lastSecondBytes = 0;
-        }
-    }, {
-        key: "addBytes",
-        value: function addBytes(bytes) {
-            if (this._firstCheckpoint === 0) {
-                this._firstCheckpoint = this._now();
-                this._lastCheckpoint = this._firstCheckpoint;
-                this._intervalBytes += bytes;
-                this._totalBytes += bytes;
-            } else if (this._now() - this._lastCheckpoint < 1000) {
-                this._intervalBytes += bytes;
-                this._totalBytes += bytes;
-            } else {
-                // duration >= 1000
-                this._lastSecondBytes = this._intervalBytes;
-                this._intervalBytes = bytes;
-                this._totalBytes += bytes;
-                this._lastCheckpoint = this._now();
-            }
-        }
-    }, {
-        key: "currentKBps",
-        get: function get() {
-            this.addBytes(0);
-
-            var durationSeconds = (this._now() - this._lastCheckpoint) / 1000;
-            if (durationSeconds == 0) durationSeconds = 1;
-            return this._intervalBytes / durationSeconds / 1024;
-        }
-    }, {
-        key: "lastSecondKBps",
-        get: function get() {
-            this.addBytes(0);
-
-            if (this._lastSecondBytes !== 0) {
-                return this._lastSecondBytes / 1024;
-            } else {
-                // lastSecondBytes === 0
-                if (this._now() - this._lastCheckpoint >= 500) {
-                    // if time interval since last checkpoint has exceeded 500ms
-                    // the speed is nearly accurate
-                    return this.currentKBps;
-                } else {
-                    // We don't know
-                    return 0;
-                }
-            }
-        }
-    }, {
-        key: "averageKBps",
-        get: function get() {
-            var durationSeconds = (this._now() - this._firstCheckpoint) / 1000;
-            return this._totalBytes / durationSeconds / 1024;
-        }
-    }]);
-
-    return SpeedSampler;
-}();
-
-exports.default = SpeedSampler;
-
-},{}],28:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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); } };
-
-var _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; }; }();
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _loader = _dereq_('./loader.js');
-
-var _exception = _dereq_('../utils/exception.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _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; }
-
-function _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; } /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
-
-// For FLV over WebSocket live stream
-var WebSocketLoader = function (_BaseLoader) {
-    _inherits(WebSocketLoader, _BaseLoader);
-
-    _createClass(WebSocketLoader, null, [{
-        key: 'isSupported',
-        value: function isSupported() {
-            try {
-                return typeof self.WebSocket !== 'undefined';
-            } catch (e) {
-                return false;
-            }
-        }
-    }]);
-
-    function WebSocketLoader() {
-        _classCallCheck(this, WebSocketLoader);
-
-        var _this = _possibleConstructorReturn(this, (WebSocketLoader.__proto__ || Object.getPrototypeOf(WebSocketLoader)).call(this, 'websocket-loader'));
-
-        _this.TAG = 'WebSocketLoader';
-
-        _this._needStash = true;
-
-        _this._ws = null;
-        _this._requestAbort = false;
-        _this._receivedLength = 0;
-        return _this;
-    }
-
-    _createClass(WebSocketLoader, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this._ws) {
-                this.abort();
-            }
-            _get(WebSocketLoader.prototype.__proto__ || Object.getPrototypeOf(WebSocketLoader.prototype), 'destroy', this).call(this);
-        }
-    }, {
-        key: 'open',
-        value: function open(dataSource) {
-            try {
-                var ws = this._ws = new self.WebSocket(dataSource.url);
-                ws.binaryType = 'arraybuffer';
-                ws.onopen = this._onWebSocketOpen.bind(this);
-                ws.onclose = this._onWebSocketClose.bind(this);
-                ws.onmessage = this._onWebSocketMessage.bind(this);
-                ws.onerror = this._onWebSocketError.bind(this);
-
-                this._status = _loader.LoaderStatus.kConnecting;
-            } catch (e) {
-                this._status = _loader.LoaderStatus.kError;
-
-                var info = { code: e.code, msg: e.message };
-
-                if (this._onError) {
-                    this._onError(_loader.LoaderErrors.EXCEPTION, info);
-                } else {
-                    throw new _exception.RuntimeException(info.msg);
-                }
-            }
-        }
-    }, {
-        key: 'abort',
-        value: function abort() {
-            var ws = this._ws;
-            if (ws && (ws.readyState === 0 || ws.readyState === 1)) {
-                // CONNECTING || OPEN
-                this._requestAbort = true;
-                ws.close();
-            }
-
-            this._ws = null;
-            this._status = _loader.LoaderStatus.kComplete;
-        }
-    }, {
-        key: '_onWebSocketOpen',
-        value: function _onWebSocketOpen(e) {
-            this._status = _loader.LoaderStatus.kBuffering;
-        }
-    }, {
-        key: '_onWebSocketClose',
-        value: function _onWebSocketClose(e) {
-            if (this._requestAbort === true) {
-                this._requestAbort = false;
-                return;
-            }
-
-            this._status = _loader.LoaderStatus.kComplete;
-
-            if (this._onComplete) {
-                this._onComplete(0, this._receivedLength - 1);
-            }
-        }
-    }, {
-        key: '_onWebSocketMessage',
-        value: function _onWebSocketMessage(e) {
-            var _this2 = this;
-
-            if (e.data instanceof ArrayBuffer) {
-                this._dispatchArrayBuffer(e.data);
-            } else if (e.data instanceof Blob) {
-                var reader = new FileReader();
-                reader.onload = function () {
-                    _this2._dispatchArrayBuffer(reader.result);
-                };
-                reader.readAsArrayBuffer(e.data);
-            } else {
-                this._status = _loader.LoaderStatus.kError;
-                var info = { code: -1, msg: 'Unsupported WebSocket message type: ' + e.data.constructor.name };
-
-                if (this._onError) {
-                    this._onError(_loader.LoaderErrors.EXCEPTION, info);
-                } else {
-                    throw new _exception.RuntimeException(info.msg);
-                }
-            }
-        }
-    }, {
-        key: '_dispatchArrayBuffer',
-        value: function _dispatchArrayBuffer(arraybuffer) {
-            var chunk = arraybuffer;
-            var byteStart = this._receivedLength;
-            this._receivedLength += chunk.byteLength;
-
-            if (this._onDataArrival) {
-                this._onDataArrival(chunk, byteStart, this._receivedLength);
-            }
-        }
-    }, {
-        key: '_onWebSocketError',
-        value: function _onWebSocketError(e) {
-            this._status = _loader.LoaderStatus.kError;
-
-            var info = {
-                code: e.code,
-                msg: e.message
-            };
-
-            if (this._onError) {
-                this._onError(_loader.LoaderErrors.EXCEPTION, info);
-            } else {
-                throw new _exception.RuntimeException(info.msg);
-            }
-        }
-    }]);
-
-    return WebSocketLoader;
-}(_loader.BaseLoader);
-
-exports.default = WebSocketLoader;
-
-},{"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24}],29:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; };
-
-var _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); } };
-
-var _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; }; }();
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _loader = _dereq_('./loader.js');
-
-var _exception = _dereq_('../utils/exception.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _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; }
-
-function _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; } /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
-
-// For FireFox browser which supports `xhr.responseType = 'moz-chunked-arraybuffer'`
-var MozChunkedLoader = function (_BaseLoader) {
-    _inherits(MozChunkedLoader, _BaseLoader);
-
-    _createClass(MozChunkedLoader, null, [{
-        key: 'isSupported',
-        value: function isSupported() {
-            try {
-                var xhr = new XMLHttpRequest();
-                // Firefox 37- requires .open() to be called before setting responseType
-                xhr.open('GET', 'https://example.com', true);
-                xhr.responseType = 'moz-chunked-arraybuffer';
-                return xhr.responseType === 'moz-chunked-arraybuffer';
-            } catch (e) {
-                _logger2.default.w('MozChunkedLoader', e.message);
-                return false;
-            }
-        }
-    }]);
-
-    function MozChunkedLoader(seekHandler, config) {
-        _classCallCheck(this, MozChunkedLoader);
-
-        var _this = _possibleConstructorReturn(this, (MozChunkedLoader.__proto__ || Object.getPrototypeOf(MozChunkedLoader)).call(this, 'xhr-moz-chunked-loader'));
-
-        _this.TAG = 'MozChunkedLoader';
-
-        _this._seekHandler = seekHandler;
-        _this._config = config;
-        _this._needStash = true;
-
-        _this._xhr = null;
-        _this._requestAbort = false;
-        _this._contentLength = null;
-        _this._receivedLength = 0;
-        return _this;
-    }
-
-    _createClass(MozChunkedLoader, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this.isWorking()) {
-                this.abort();
-            }
-            if (this._xhr) {
-                this._xhr.onreadystatechange = null;
-                this._xhr.onprogress = null;
-                this._xhr.onloadend = null;
-                this._xhr.onerror = null;
-                this._xhr = null;
-            }
-            _get(MozChunkedLoader.prototype.__proto__ || Object.getPrototypeOf(MozChunkedLoader.prototype), 'destroy', this).call(this);
-        }
-    }, {
-        key: 'open',
-        value: function open(dataSource, range) {
-            this._dataSource = dataSource;
-            this._range = range;
-
-            var sourceURL = dataSource.url;
-            if (this._config.reuseRedirectedURL && dataSource.redirectedURL != undefined) {
-                sourceURL = dataSource.redirectedURL;
-            }
-
-            var seekConfig = this._seekHandler.getConfig(sourceURL, range);
-            this._requestURL = seekConfig.url;
-
-            var xhr = this._xhr = new XMLHttpRequest();
-            xhr.open('GET', seekConfig.url, true);
-            xhr.responseType = 'moz-chunked-arraybuffer';
-            xhr.onreadystatechange = this._onReadyStateChange.bind(this);
-            xhr.onprogress = this._onProgress.bind(this);
-            xhr.onloadend = this._onLoadEnd.bind(this);
-            xhr.onerror = this._onXhrError.bind(this);
-
-            // cors is auto detected and enabled by xhr
-
-            // withCredentials is disabled by default
-            if (dataSource.withCredentials) {
-                xhr.withCredentials = true;
-            }
-
-            if (_typeof(seekConfig.headers) === 'object') {
-                var headers = seekConfig.headers;
-
-                for (var key in headers) {
-                    if (headers.hasOwnProperty(key)) {
-                        xhr.setRequestHeader(key, headers[key]);
+                        return resultParams.length === 0 ? baseURL : baseURL + '?' + resultParams;
                     }
+                }]);
+
+                return ParamSeekHandler;
+            }();
+
+            exports.default = ParamSeekHandler;
+
+        }, {}], 26: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }();
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var RangeSeekHandler = function () {
+                function RangeSeekHandler(zeroStart) {
+                    _classCallCheck(this, RangeSeekHandler);
+
+                    this._zeroStart = zeroStart || false;
                 }
-            }
 
-            // add additional headers
-            if (_typeof(this._config.headers) === 'object') {
-                var _headers = this._config.headers;
+                _createClass(RangeSeekHandler, [{
+                    key: 'getConfig',
+                    value: function getConfig(url, range) {
+                        var headers = {};
 
-                for (var _key in _headers) {
-                    if (_headers.hasOwnProperty(_key)) {
-                        xhr.setRequestHeader(_key, _headers[_key]);
+                        if (range.from !== 0 || range.to !== -1) {
+                            var param = void 0;
+                            if (range.to !== -1) {
+                                param = 'bytes=' + range.from.toString() + '-' + range.to.toString();
+                            } else {
+                                param = 'bytes=' + range.from.toString() + '-';
+                            }
+                            headers['Range'] = param;
+                        } else if (this._zeroStart) {
+                            headers['Range'] = 'bytes=0-';
+                        }
+
+                        return {
+                            url: url,
+                            headers: headers
+                        };
                     }
-                }
-            }
-
-            this._status = _loader.LoaderStatus.kConnecting;
-            xhr.send();
-        }
-    }, {
-        key: 'abort',
-        value: function abort() {
-            this._requestAbort = true;
-            if (this._xhr) {
-                this._xhr.abort();
-            }
-            this._status = _loader.LoaderStatus.kComplete;
-        }
-    }, {
-        key: '_onReadyStateChange',
-        value: function _onReadyStateChange(e) {
-            var xhr = e.target;
-
-            if (xhr.readyState === 2) {
-                // HEADERS_RECEIVED
-                if (xhr.responseURL != undefined && xhr.responseURL !== this._requestURL) {
-                    if (this._onURLRedirect) {
-                        var redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
-                        this._onURLRedirect(redirectedURL);
+                }, {
+                    key: 'removeURLParameters',
+                    value: function removeURLParameters(seekedURL) {
+                        return seekedURL;
                     }
-                }
+                }]);
 
-                if (xhr.status !== 0 && (xhr.status < 200 || xhr.status > 299)) {
-                    this._status = _loader.LoaderStatus.kError;
-                    if (this._onError) {
-                        this._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: xhr.status, msg: xhr.statusText });
+                return RangeSeekHandler;
+            }();
+
+            exports.default = RangeSeekHandler;
+
+        }, {}], 27: [function (_dereq_, module, exports) {
+            "use strict";
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }();
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            // Utility class to calculate realtime network I/O speed
+            var SpeedSampler = function () {
+                function SpeedSampler() {
+                    _classCallCheck(this, SpeedSampler);
+
+                    // milliseconds
+                    this._firstCheckpoint = 0;
+                    this._lastCheckpoint = 0;
+                    this._intervalBytes = 0;
+                    this._totalBytes = 0;
+                    this._lastSecondBytes = 0;
+
+                    // compatibility detection
+                    if (self.performance && self.performance.now) {
+                        this._now = self.performance.now.bind(self.performance);
                     } else {
-                        throw new _exception.RuntimeException('MozChunkedLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
-                    }
-                } else {
-                    this._status = _loader.LoaderStatus.kBuffering;
-                }
-            }
-        }
-    }, {
-        key: '_onProgress',
-        value: function _onProgress(e) {
-            if (this._status === _loader.LoaderStatus.kError) {
-                // Ignore error response
-                return;
-            }
-
-            if (this._contentLength === null) {
-                if (e.total !== null && e.total !== 0) {
-                    this._contentLength = e.total;
-                    if (this._onContentLengthKnown) {
-                        this._onContentLengthKnown(this._contentLength);
+                        this._now = Date.now;
                     }
                 }
-            }
 
-            var chunk = e.target.response;
-            var byteStart = this._range.from + this._receivedLength;
-            this._receivedLength += chunk.byteLength;
-
-            if (this._onDataArrival) {
-                this._onDataArrival(chunk, byteStart, this._receivedLength);
-            }
-        }
-    }, {
-        key: '_onLoadEnd',
-        value: function _onLoadEnd(e) {
-            if (this._requestAbort === true) {
-                this._requestAbort = false;
-                return;
-            } else if (this._status === _loader.LoaderStatus.kError) {
-                return;
-            }
-
-            this._status = _loader.LoaderStatus.kComplete;
-            if (this._onComplete) {
-                this._onComplete(this._range.from, this._range.from + this._receivedLength - 1);
-            }
-        }
-    }, {
-        key: '_onXhrError',
-        value: function _onXhrError(e) {
-            this._status = _loader.LoaderStatus.kError;
-            var type = 0;
-            var info = null;
-
-            if (this._contentLength && e.loaded < this._contentLength) {
-                type = _loader.LoaderErrors.EARLY_EOF;
-                info = { code: -1, msg: 'Moz-Chunked stream meet Early-Eof' };
-            } else {
-                type = _loader.LoaderErrors.EXCEPTION;
-                info = { code: -1, msg: e.constructor.name + ' ' + e.type };
-            }
-
-            if (this._onError) {
-                this._onError(type, info);
-            } else {
-                throw new _exception.RuntimeException(info.msg);
-            }
-        }
-    }]);
-
-    return MozChunkedLoader;
-}(_loader.BaseLoader);
-
-exports.default = MozChunkedLoader;
-
-},{"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24}],30:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; };
-
-var _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); } };
-
-var _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; }; }();
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _loader = _dereq_('./loader.js');
-
-var _exception = _dereq_('../utils/exception.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _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; }
-
-function _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; } /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
-
-/* Notice: ms-stream may cause IE/Edge browser crash if seek too frequently!!!
- * The browser may crash in wininet.dll. Disable for now.
- *
- * For IE11/Edge browser by microsoft which supports `xhr.responseType = 'ms-stream'`
- * Notice that ms-stream API sucks. The buffer is always expanding along with downloading.
- *
- * We need to abort the xhr if buffer size exceeded limit size (e.g. 16 MiB), then do reconnect.
- * in order to release previous ArrayBuffer to avoid memory leak
- *
- * Otherwise, the ArrayBuffer will increase to a terrible size that equals final file size.
- */
-var MSStreamLoader = function (_BaseLoader) {
-    _inherits(MSStreamLoader, _BaseLoader);
-
-    _createClass(MSStreamLoader, null, [{
-        key: 'isSupported',
-        value: function isSupported() {
-            try {
-                if (typeof self.MSStream === 'undefined' || typeof self.MSStreamReader === 'undefined') {
-                    return false;
-                }
-
-                var xhr = new XMLHttpRequest();
-                xhr.open('GET', 'https://example.com', true);
-                xhr.responseType = 'ms-stream';
-                return xhr.responseType === 'ms-stream';
-            } catch (e) {
-                _logger2.default.w('MSStreamLoader', e.message);
-                return false;
-            }
-        }
-    }]);
-
-    function MSStreamLoader(seekHandler, config) {
-        _classCallCheck(this, MSStreamLoader);
-
-        var _this = _possibleConstructorReturn(this, (MSStreamLoader.__proto__ || Object.getPrototypeOf(MSStreamLoader)).call(this, 'xhr-msstream-loader'));
-
-        _this.TAG = 'MSStreamLoader';
-
-        _this._seekHandler = seekHandler;
-        _this._config = config;
-        _this._needStash = true;
-
-        _this._xhr = null;
-        _this._reader = null; // MSStreamReader
-
-        _this._totalRange = null;
-        _this._currentRange = null;
-
-        _this._currentRequestURL = null;
-        _this._currentRedirectedURL = null;
-
-        _this._contentLength = null;
-        _this._receivedLength = 0;
-
-        _this._bufferLimit = 16 * 1024 * 1024; // 16MB
-        _this._lastTimeBufferSize = 0;
-        _this._isReconnecting = false;
-        return _this;
-    }
-
-    _createClass(MSStreamLoader, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this.isWorking()) {
-                this.abort();
-            }
-            if (this._reader) {
-                this._reader.onprogress = null;
-                this._reader.onload = null;
-                this._reader.onerror = null;
-                this._reader = null;
-            }
-            if (this._xhr) {
-                this._xhr.onreadystatechange = null;
-                this._xhr = null;
-            }
-            _get(MSStreamLoader.prototype.__proto__ || Object.getPrototypeOf(MSStreamLoader.prototype), 'destroy', this).call(this);
-        }
-    }, {
-        key: 'open',
-        value: function open(dataSource, range) {
-            this._internalOpen(dataSource, range, false);
-        }
-    }, {
-        key: '_internalOpen',
-        value: function _internalOpen(dataSource, range, isSubrange) {
-            this._dataSource = dataSource;
-
-            if (!isSubrange) {
-                this._totalRange = range;
-            } else {
-                this._currentRange = range;
-            }
-
-            var sourceURL = dataSource.url;
-            if (this._config.reuseRedirectedURL) {
-                if (this._currentRedirectedURL != undefined) {
-                    sourceURL = this._currentRedirectedURL;
-                } else if (dataSource.redirectedURL != undefined) {
-                    sourceURL = dataSource.redirectedURL;
-                }
-            }
-
-            var seekConfig = this._seekHandler.getConfig(sourceURL, range);
-            this._currentRequestURL = seekConfig.url;
-
-            var reader = this._reader = new self.MSStreamReader();
-            reader.onprogress = this._msrOnProgress.bind(this);
-            reader.onload = this._msrOnLoad.bind(this);
-            reader.onerror = this._msrOnError.bind(this);
-
-            var xhr = this._xhr = new XMLHttpRequest();
-            xhr.open('GET', seekConfig.url, true);
-            xhr.responseType = 'ms-stream';
-            xhr.onreadystatechange = this._xhrOnReadyStateChange.bind(this);
-            xhr.onerror = this._xhrOnError.bind(this);
-
-            if (dataSource.withCredentials) {
-                xhr.withCredentials = true;
-            }
-
-            if (_typeof(seekConfig.headers) === 'object') {
-                var headers = seekConfig.headers;
-
-                for (var key in headers) {
-                    if (headers.hasOwnProperty(key)) {
-                        xhr.setRequestHeader(key, headers[key]);
+                _createClass(SpeedSampler, [{
+                    key: "reset",
+                    value: function reset() {
+                        this._firstCheckpoint = this._lastCheckpoint = 0;
+                        this._totalBytes = this._intervalBytes = 0;
+                        this._lastSecondBytes = 0;
                     }
-                }
-            }
-
-            // add additional headers
-            if (_typeof(this._config.headers) === 'object') {
-                var _headers = this._config.headers;
-
-                for (var _key in _headers) {
-                    if (_headers.hasOwnProperty(_key)) {
-                        xhr.setRequestHeader(_key, _headers[_key]);
+                }, {
+                    key: "addBytes",
+                    value: function addBytes(bytes) {
+                        if (this._firstCheckpoint === 0) {
+                            this._firstCheckpoint = this._now();
+                            this._lastCheckpoint = this._firstCheckpoint;
+                            this._intervalBytes += bytes;
+                            this._totalBytes += bytes;
+                        } else if (this._now() - this._lastCheckpoint < 1000) {
+                            this._intervalBytes += bytes;
+                            this._totalBytes += bytes;
+                        } else {
+                            // duration >= 1000
+                            this._lastSecondBytes = this._intervalBytes;
+                            this._intervalBytes = bytes;
+                            this._totalBytes += bytes;
+                            this._lastCheckpoint = this._now();
+                        }
                     }
-                }
-            }
+                }, {
+                    key: "currentKBps",
+                    get: function get() {
+                        this.addBytes(0);
 
-            if (this._isReconnecting) {
-                this._isReconnecting = false;
-            } else {
-                this._status = _loader.LoaderStatus.kConnecting;
-            }
-            xhr.send();
-        }
-    }, {
-        key: 'abort',
-        value: function abort() {
-            this._internalAbort();
-            this._status = _loader.LoaderStatus.kComplete;
-        }
-    }, {
-        key: '_internalAbort',
-        value: function _internalAbort() {
-            if (this._reader) {
-                if (this._reader.readyState === 1) {
-                    // LOADING
-                    this._reader.abort();
-                }
-                this._reader.onprogress = null;
-                this._reader.onload = null;
-                this._reader.onerror = null;
-                this._reader = null;
-            }
-            if (this._xhr) {
-                this._xhr.abort();
-                this._xhr.onreadystatechange = null;
-                this._xhr = null;
-            }
-        }
-    }, {
-        key: '_xhrOnReadyStateChange',
-        value: function _xhrOnReadyStateChange(e) {
-            var xhr = e.target;
+                        var durationSeconds = (this._now() - this._lastCheckpoint) / 1000;
+                        if (durationSeconds == 0) durationSeconds = 1;
+                        return this._intervalBytes / durationSeconds / 1024;
+                    }
+                }, {
+                    key: "lastSecondKBps",
+                    get: function get() {
+                        this.addBytes(0);
 
-            if (xhr.readyState === 2) {
-                // HEADERS_RECEIVED
-                if (xhr.status >= 200 && xhr.status <= 299) {
-                    this._status = _loader.LoaderStatus.kBuffering;
-
-                    if (xhr.responseURL != undefined) {
-                        var redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
-                        if (xhr.responseURL !== this._currentRequestURL && redirectedURL !== this._currentRedirectedURL) {
-                            this._currentRedirectedURL = redirectedURL;
-                            if (this._onURLRedirect) {
-                                this._onURLRedirect(redirectedURL);
+                        if (this._lastSecondBytes !== 0) {
+                            return this._lastSecondBytes / 1024;
+                        } else {
+                            // lastSecondBytes === 0
+                            if (this._now() - this._lastCheckpoint >= 500) {
+                                // if time interval since last checkpoint has exceeded 500ms
+                                // the speed is nearly accurate
+                                return this.currentKBps;
+                            } else {
+                                // We don't know
+                                return 0;
                             }
                         }
                     }
+                }, {
+                    key: "averageKBps",
+                    get: function get() {
+                        var durationSeconds = (this._now() - this._firstCheckpoint) / 1000;
+                        return this._totalBytes / durationSeconds / 1024;
+                    }
+                }]);
 
-                    var lengthHeader = xhr.getResponseHeader('Content-Length');
-                    if (lengthHeader != null && this._contentLength == null) {
-                        var length = parseInt(lengthHeader);
-                        if (length > 0) {
-                            this._contentLength = length;
+                return SpeedSampler;
+            }();
+
+            exports.default = SpeedSampler;
+
+        }, {}], 28: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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); } };
+
+            var _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; }; }();
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _loader = _dereq_('./loader.js');
+
+            var _exception = _dereq_('../utils/exception.js');
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            function _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; }
+
+            function _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; } /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+
+            // For FLV over WebSocket live stream
+            var WebSocketLoader = function (_BaseLoader) {
+                _inherits(WebSocketLoader, _BaseLoader);
+
+                _createClass(WebSocketLoader, null, [{
+                    key: 'isSupported',
+                    value: function isSupported() {
+                        try {
+                            return typeof self.WebSocket !== 'undefined';
+                        } catch (e) {
+                            return false;
+                        }
+                    }
+                }]);
+
+                function WebSocketLoader() {
+                    _classCallCheck(this, WebSocketLoader);
+
+                    var _this = _possibleConstructorReturn(this, (WebSocketLoader.__proto__ || Object.getPrototypeOf(WebSocketLoader)).call(this, 'websocket-loader'));
+
+                    _this.TAG = 'WebSocketLoader';
+
+                    _this._needStash = true;
+
+                    _this._ws = null;
+                    _this._requestAbort = false;
+                    _this._receivedLength = 0;
+                    return _this;
+                }
+
+                _createClass(WebSocketLoader, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        if (this._ws) {
+                            this.abort();
+                        }
+                        _get(WebSocketLoader.prototype.__proto__ || Object.getPrototypeOf(WebSocketLoader.prototype), 'destroy', this).call(this);
+                    }
+                }, {
+                    key: 'open',
+                    value: function open(dataSource) {
+                        try {
+                            var ws = this._ws = new self.WebSocket(dataSource.url);
+                            ws.binaryType = 'arraybuffer';
+                            ws.onopen = this._onWebSocketOpen.bind(this);
+                            ws.onclose = this._onWebSocketClose.bind(this);
+                            ws.onmessage = this._onWebSocketMessage.bind(this);
+                            ws.onerror = this._onWebSocketError.bind(this);
+
+                            this._status = _loader.LoaderStatus.kConnecting;
+                        } catch (e) {
+                            this._status = _loader.LoaderStatus.kError;
+
+                            var info = { code: e.code, msg: e.message };
+
+                            if (this._onError) {
+                                this._onError(_loader.LoaderErrors.EXCEPTION, info);
+                            } else {
+                                throw new _exception.RuntimeException(info.msg);
+                            }
+                        }
+                    }
+                }, {
+                    key: 'abort',
+                    value: function abort() {
+                        var ws = this._ws;
+                        if (ws && (ws.readyState === 0 || ws.readyState === 1)) {
+                            // CONNECTING || OPEN
+                            this._requestAbort = true;
+                            ws.close();
+                        }
+
+                        this._ws = null;
+                        this._status = _loader.LoaderStatus.kComplete;
+                    }
+                }, {
+                    key: '_onWebSocketOpen',
+                    value: function _onWebSocketOpen(e) {
+                        this._status = _loader.LoaderStatus.kBuffering;
+                    }
+                }, {
+                    key: '_onWebSocketClose',
+                    value: function _onWebSocketClose(e) {
+                        if (this._requestAbort === true) {
+                            this._requestAbort = false;
+                            return;
+                        }
+
+                        this._status = _loader.LoaderStatus.kComplete;
+
+                        if (this._onComplete) {
+                            this._onComplete(0, this._receivedLength - 1);
+                        }
+                    }
+                }, {
+                    key: '_onWebSocketMessage',
+                    value: function _onWebSocketMessage(e) {
+                        var _this2 = this;
+
+                        if (e.data instanceof ArrayBuffer) {
+                            this._dispatchArrayBuffer(e.data);
+                        } else if (e.data instanceof Blob) {
+                            var reader = new FileReader();
+                            reader.onload = function () {
+                                _this2._dispatchArrayBuffer(reader.result);
+                            };
+                            reader.readAsArrayBuffer(e.data);
+                        } else {
+                            this._status = _loader.LoaderStatus.kError;
+                            var info = { code: -1, msg: 'Unsupported WebSocket message type: ' + e.data.constructor.name };
+
+                            if (this._onError) {
+                                this._onError(_loader.LoaderErrors.EXCEPTION, info);
+                            } else {
+                                throw new _exception.RuntimeException(info.msg);
+                            }
+                        }
+                    }
+                }, {
+                    key: '_dispatchArrayBuffer',
+                    value: function _dispatchArrayBuffer(arraybuffer) {
+                        var chunk = arraybuffer;
+                        var byteStart = this._receivedLength;
+                        this._receivedLength += chunk.byteLength;
+
+                        if (this._onDataArrival) {
+                            this._onDataArrival(chunk, byteStart, this._receivedLength);
+                        }
+                    }
+                }, {
+                    key: '_onWebSocketError',
+                    value: function _onWebSocketError(e) {
+                        this._status = _loader.LoaderStatus.kError;
+
+                        var info = {
+                            code: e.code,
+                            msg: e.message
+                        };
+
+                        if (this._onError) {
+                            this._onError(_loader.LoaderErrors.EXCEPTION, info);
+                        } else {
+                            throw new _exception.RuntimeException(info.msg);
+                        }
+                    }
+                }]);
+
+                return WebSocketLoader;
+            }(_loader.BaseLoader);
+
+            exports.default = WebSocketLoader;
+
+        }, { "../utils/exception.js": 40, "../utils/logger.js": 41, "./loader.js": 24 }], 29: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; };
+
+            var _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); } };
+
+            var _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; }; }();
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _loader = _dereq_('./loader.js');
+
+            var _exception = _dereq_('../utils/exception.js');
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            function _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; }
+
+            function _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; } /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+
+            // For FireFox browser which supports `xhr.responseType = 'moz-chunked-arraybuffer'`
+            var MozChunkedLoader = function (_BaseLoader) {
+                _inherits(MozChunkedLoader, _BaseLoader);
+
+                _createClass(MozChunkedLoader, null, [{
+                    key: 'isSupported',
+                    value: function isSupported() {
+                        try {
+                            var xhr = new XMLHttpRequest();
+                            // Firefox 37- requires .open() to be called before setting responseType
+                            xhr.open('GET', 'https://example.com', true);
+                            xhr.responseType = 'moz-chunked-arraybuffer';
+                            return xhr.responseType === 'moz-chunked-arraybuffer';
+                        } catch (e) {
+                            _logger2.default.w('MozChunkedLoader', e.message);
+                            return false;
+                        }
+                    }
+                }]);
+
+                function MozChunkedLoader(seekHandler, config) {
+                    _classCallCheck(this, MozChunkedLoader);
+
+                    var _this = _possibleConstructorReturn(this, (MozChunkedLoader.__proto__ || Object.getPrototypeOf(MozChunkedLoader)).call(this, 'xhr-moz-chunked-loader'));
+
+                    _this.TAG = 'MozChunkedLoader';
+
+                    _this._seekHandler = seekHandler;
+                    _this._config = config;
+                    _this._needStash = true;
+
+                    _this._xhr = null;
+                    _this._requestAbort = false;
+                    _this._contentLength = null;
+                    _this._receivedLength = 0;
+                    return _this;
+                }
+
+                _createClass(MozChunkedLoader, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        if (this.isWorking()) {
+                            this.abort();
+                        }
+                        if (this._xhr) {
+                            this._xhr.onreadystatechange = null;
+                            this._xhr.onprogress = null;
+                            this._xhr.onloadend = null;
+                            this._xhr.onerror = null;
+                            this._xhr = null;
+                        }
+                        _get(MozChunkedLoader.prototype.__proto__ || Object.getPrototypeOf(MozChunkedLoader.prototype), 'destroy', this).call(this);
+                    }
+                }, {
+                    key: 'open',
+                    value: function open(dataSource, range) {
+                        this._dataSource = dataSource;
+                        this._range = range;
+
+                        var sourceURL = dataSource.url;
+                        if (this._config.reuseRedirectedURL && dataSource.redirectedURL != undefined) {
+                            sourceURL = dataSource.redirectedURL;
+                        }
+
+                        var seekConfig = this._seekHandler.getConfig(sourceURL, range);
+                        this._requestURL = seekConfig.url;
+
+                        var xhr = this._xhr = new XMLHttpRequest();
+                        xhr.open('GET', seekConfig.url, true);
+                        xhr.responseType = 'moz-chunked-arraybuffer';
+                        xhr.onreadystatechange = this._onReadyStateChange.bind(this);
+                        xhr.onprogress = this._onProgress.bind(this);
+                        xhr.onloadend = this._onLoadEnd.bind(this);
+                        xhr.onerror = this._onXhrError.bind(this);
+
+                        // cors is auto detected and enabled by xhr
+
+                        // withCredentials is disabled by default
+                        if (dataSource.withCredentials) {
+                            xhr.withCredentials = true;
+                        }
+
+                        if (_typeof(seekConfig.headers) === 'object') {
+                            var headers = seekConfig.headers;
+
+                            for (var key in headers) {
+                                if (headers.hasOwnProperty(key)) {
+                                    xhr.setRequestHeader(key, headers[key]);
+                                }
+                            }
+                        }
+
+                        // add additional headers
+                        if (_typeof(this._config.headers) === 'object') {
+                            var _headers = this._config.headers;
+
+                            for (var _key in _headers) {
+                                if (_headers.hasOwnProperty(_key)) {
+                                    xhr.setRequestHeader(_key, _headers[_key]);
+                                }
+                            }
+                        }
+
+                        this._status = _loader.LoaderStatus.kConnecting;
+                        xhr.send();
+                    }
+                }, {
+                    key: 'abort',
+                    value: function abort() {
+                        this._requestAbort = true;
+                        if (this._xhr) {
+                            this._xhr.abort();
+                        }
+                        this._status = _loader.LoaderStatus.kComplete;
+                    }
+                }, {
+                    key: '_onReadyStateChange',
+                    value: function _onReadyStateChange(e) {
+                        var xhr = e.target;
+
+                        if (xhr.readyState === 2) {
+                            // HEADERS_RECEIVED
+                            if (xhr.responseURL != undefined && xhr.responseURL !== this._requestURL) {
+                                if (this._onURLRedirect) {
+                                    var redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
+                                    this._onURLRedirect(redirectedURL);
+                                }
+                            }
+
+                            if (xhr.status !== 0 && (xhr.status < 200 || xhr.status > 299)) {
+                                this._status = _loader.LoaderStatus.kError;
+                                if (this._onError) {
+                                    this._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: xhr.status, msg: xhr.statusText });
+                                } else {
+                                    throw new _exception.RuntimeException('MozChunkedLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
+                                }
+                            } else {
+                                this._status = _loader.LoaderStatus.kBuffering;
+                            }
+                        }
+                    }
+                }, {
+                    key: '_onProgress',
+                    value: function _onProgress(e) {
+                        if (this._status === _loader.LoaderStatus.kError) {
+                            // Ignore error response
+                            return;
+                        }
+
+                        if (this._contentLength === null) {
+                            if (e.total !== null && e.total !== 0) {
+                                this._contentLength = e.total;
+                                if (this._onContentLengthKnown) {
+                                    this._onContentLengthKnown(this._contentLength);
+                                }
+                            }
+                        }
+
+                        var chunk = e.target.response;
+                        var byteStart = this._range.from + this._receivedLength;
+                        this._receivedLength += chunk.byteLength;
+
+                        if (this._onDataArrival) {
+                            this._onDataArrival(chunk, byteStart, this._receivedLength);
+                        }
+                    }
+                }, {
+                    key: '_onLoadEnd',
+                    value: function _onLoadEnd(e) {
+                        if (this._requestAbort === true) {
+                            this._requestAbort = false;
+                            return;
+                        } else if (this._status === _loader.LoaderStatus.kError) {
+                            return;
+                        }
+
+                        this._status = _loader.LoaderStatus.kComplete;
+                        if (this._onComplete) {
+                            this._onComplete(this._range.from, this._range.from + this._receivedLength - 1);
+                        }
+                    }
+                }, {
+                    key: '_onXhrError',
+                    value: function _onXhrError(e) {
+                        this._status = _loader.LoaderStatus.kError;
+                        var type = 0;
+                        var info = null;
+
+                        if (this._contentLength && e.loaded < this._contentLength) {
+                            type = _loader.LoaderErrors.EARLY_EOF;
+                            info = { code: -1, msg: 'Moz-Chunked stream meet Early-Eof' };
+                        } else {
+                            type = _loader.LoaderErrors.EXCEPTION;
+                            info = { code: -1, msg: e.constructor.name + ' ' + e.type };
+                        }
+
+                        if (this._onError) {
+                            this._onError(type, info);
+                        } else {
+                            throw new _exception.RuntimeException(info.msg);
+                        }
+                    }
+                }]);
+
+                return MozChunkedLoader;
+            }(_loader.BaseLoader);
+
+            exports.default = MozChunkedLoader;
+
+        }, { "../utils/exception.js": 40, "../utils/logger.js": 41, "./loader.js": 24 }], 30: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; };
+
+            var _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); } };
+
+            var _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; }; }();
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _loader = _dereq_('./loader.js');
+
+            var _exception = _dereq_('../utils/exception.js');
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            function _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; }
+
+            function _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; } /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+
+            /* Notice: ms-stream may cause IE/Edge browser crash if seek too frequently!!!
+             * The browser may crash in wininet.dll. Disable for now.
+             *
+             * For IE11/Edge browser by microsoft which supports `xhr.responseType = 'ms-stream'`
+             * Notice that ms-stream API sucks. The buffer is always expanding along with downloading.
+             *
+             * We need to abort the xhr if buffer size exceeded limit size (e.g. 16 MiB), then do reconnect.
+             * in order to release previous ArrayBuffer to avoid memory leak
+             *
+             * Otherwise, the ArrayBuffer will increase to a terrible size that equals final file size.
+             */
+            var MSStreamLoader = function (_BaseLoader) {
+                _inherits(MSStreamLoader, _BaseLoader);
+
+                _createClass(MSStreamLoader, null, [{
+                    key: 'isSupported',
+                    value: function isSupported() {
+                        try {
+                            if (typeof self.MSStream === 'undefined' || typeof self.MSStreamReader === 'undefined') {
+                                return false;
+                            }
+
+                            var xhr = new XMLHttpRequest();
+                            xhr.open('GET', 'https://example.com', true);
+                            xhr.responseType = 'ms-stream';
+                            return xhr.responseType === 'ms-stream';
+                        } catch (e) {
+                            _logger2.default.w('MSStreamLoader', e.message);
+                            return false;
+                        }
+                    }
+                }]);
+
+                function MSStreamLoader(seekHandler, config) {
+                    _classCallCheck(this, MSStreamLoader);
+
+                    var _this = _possibleConstructorReturn(this, (MSStreamLoader.__proto__ || Object.getPrototypeOf(MSStreamLoader)).call(this, 'xhr-msstream-loader'));
+
+                    _this.TAG = 'MSStreamLoader';
+
+                    _this._seekHandler = seekHandler;
+                    _this._config = config;
+                    _this._needStash = true;
+
+                    _this._xhr = null;
+                    _this._reader = null; // MSStreamReader
+
+                    _this._totalRange = null;
+                    _this._currentRange = null;
+
+                    _this._currentRequestURL = null;
+                    _this._currentRedirectedURL = null;
+
+                    _this._contentLength = null;
+                    _this._receivedLength = 0;
+
+                    _this._bufferLimit = 16 * 1024 * 1024; // 16MB
+                    _this._lastTimeBufferSize = 0;
+                    _this._isReconnecting = false;
+                    return _this;
+                }
+
+                _createClass(MSStreamLoader, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        if (this.isWorking()) {
+                            this.abort();
+                        }
+                        if (this._reader) {
+                            this._reader.onprogress = null;
+                            this._reader.onload = null;
+                            this._reader.onerror = null;
+                            this._reader = null;
+                        }
+                        if (this._xhr) {
+                            this._xhr.onreadystatechange = null;
+                            this._xhr = null;
+                        }
+                        _get(MSStreamLoader.prototype.__proto__ || Object.getPrototypeOf(MSStreamLoader.prototype), 'destroy', this).call(this);
+                    }
+                }, {
+                    key: 'open',
+                    value: function open(dataSource, range) {
+                        this._internalOpen(dataSource, range, false);
+                    }
+                }, {
+                    key: '_internalOpen',
+                    value: function _internalOpen(dataSource, range, isSubrange) {
+                        this._dataSource = dataSource;
+
+                        if (!isSubrange) {
+                            this._totalRange = range;
+                        } else {
+                            this._currentRange = range;
+                        }
+
+                        var sourceURL = dataSource.url;
+                        if (this._config.reuseRedirectedURL) {
+                            if (this._currentRedirectedURL != undefined) {
+                                sourceURL = this._currentRedirectedURL;
+                            } else if (dataSource.redirectedURL != undefined) {
+                                sourceURL = dataSource.redirectedURL;
+                            }
+                        }
+
+                        var seekConfig = this._seekHandler.getConfig(sourceURL, range);
+                        this._currentRequestURL = seekConfig.url;
+
+                        var reader = this._reader = new self.MSStreamReader();
+                        reader.onprogress = this._msrOnProgress.bind(this);
+                        reader.onload = this._msrOnLoad.bind(this);
+                        reader.onerror = this._msrOnError.bind(this);
+
+                        var xhr = this._xhr = new XMLHttpRequest();
+                        xhr.open('GET', seekConfig.url, true);
+                        xhr.responseType = 'ms-stream';
+                        xhr.onreadystatechange = this._xhrOnReadyStateChange.bind(this);
+                        xhr.onerror = this._xhrOnError.bind(this);
+
+                        if (dataSource.withCredentials) {
+                            xhr.withCredentials = true;
+                        }
+
+                        if (_typeof(seekConfig.headers) === 'object') {
+                            var headers = seekConfig.headers;
+
+                            for (var key in headers) {
+                                if (headers.hasOwnProperty(key)) {
+                                    xhr.setRequestHeader(key, headers[key]);
+                                }
+                            }
+                        }
+
+                        // add additional headers
+                        if (_typeof(this._config.headers) === 'object') {
+                            var _headers = this._config.headers;
+
+                            for (var _key in _headers) {
+                                if (_headers.hasOwnProperty(_key)) {
+                                    xhr.setRequestHeader(_key, _headers[_key]);
+                                }
+                            }
+                        }
+
+                        if (this._isReconnecting) {
+                            this._isReconnecting = false;
+                        } else {
+                            this._status = _loader.LoaderStatus.kConnecting;
+                        }
+                        xhr.send();
+                    }
+                }, {
+                    key: 'abort',
+                    value: function abort() {
+                        this._internalAbort();
+                        this._status = _loader.LoaderStatus.kComplete;
+                    }
+                }, {
+                    key: '_internalAbort',
+                    value: function _internalAbort() {
+                        if (this._reader) {
+                            if (this._reader.readyState === 1) {
+                                // LOADING
+                                this._reader.abort();
+                            }
+                            this._reader.onprogress = null;
+                            this._reader.onload = null;
+                            this._reader.onerror = null;
+                            this._reader = null;
+                        }
+                        if (this._xhr) {
+                            this._xhr.abort();
+                            this._xhr.onreadystatechange = null;
+                            this._xhr = null;
+                        }
+                    }
+                }, {
+                    key: '_xhrOnReadyStateChange',
+                    value: function _xhrOnReadyStateChange(e) {
+                        var xhr = e.target;
+
+                        if (xhr.readyState === 2) {
+                            // HEADERS_RECEIVED
+                            if (xhr.status >= 200 && xhr.status <= 299) {
+                                this._status = _loader.LoaderStatus.kBuffering;
+
+                                if (xhr.responseURL != undefined) {
+                                    var redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
+                                    if (xhr.responseURL !== this._currentRequestURL && redirectedURL !== this._currentRedirectedURL) {
+                                        this._currentRedirectedURL = redirectedURL;
+                                        if (this._onURLRedirect) {
+                                            this._onURLRedirect(redirectedURL);
+                                        }
+                                    }
+                                }
+
+                                var lengthHeader = xhr.getResponseHeader('Content-Length');
+                                if (lengthHeader != null && this._contentLength == null) {
+                                    var length = parseInt(lengthHeader);
+                                    if (length > 0) {
+                                        this._contentLength = length;
+                                        if (this._onContentLengthKnown) {
+                                            this._onContentLengthKnown(this._contentLength);
+                                        }
+                                    }
+                                }
+                            } else {
+                                this._status = _loader.LoaderStatus.kError;
+                                if (this._onError) {
+                                    this._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: xhr.status, msg: xhr.statusText });
+                                } else {
+                                    throw new _exception.RuntimeException('MSStreamLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
+                                }
+                            }
+                        } else if (xhr.readyState === 3) {
+                            // LOADING
+                            if (xhr.status >= 200 && xhr.status <= 299) {
+                                this._status = _loader.LoaderStatus.kBuffering;
+
+                                var msstream = xhr.response;
+                                this._reader.readAsArrayBuffer(msstream);
+                            }
+                        }
+                    }
+                }, {
+                    key: '_xhrOnError',
+                    value: function _xhrOnError(e) {
+                        this._status = _loader.LoaderStatus.kError;
+                        var type = _loader.LoaderErrors.EXCEPTION;
+                        var info = { code: -1, msg: e.constructor.name + ' ' + e.type };
+
+                        if (this._onError) {
+                            this._onError(type, info);
+                        } else {
+                            throw new _exception.RuntimeException(info.msg);
+                        }
+                    }
+                }, {
+                    key: '_msrOnProgress',
+                    value: function _msrOnProgress(e) {
+                        var reader = e.target;
+                        var bigbuffer = reader.result;
+                        if (bigbuffer == null) {
+                            // result may be null, workaround for buggy M$
+                            this._doReconnectIfNeeded();
+                            return;
+                        }
+
+                        var slice = bigbuffer.slice(this._lastTimeBufferSize);
+                        this._lastTimeBufferSize = bigbuffer.byteLength;
+                        var byteStart = this._totalRange.from + this._receivedLength;
+                        this._receivedLength += slice.byteLength;
+
+                        if (this._onDataArrival) {
+                            this._onDataArrival(slice, byteStart, this._receivedLength);
+                        }
+
+                        if (bigbuffer.byteLength >= this._bufferLimit) {
+                            _logger2.default.v(this.TAG, 'MSStream buffer exceeded max size near ' + (byteStart + slice.byteLength) + ', reconnecting...');
+                            this._doReconnectIfNeeded();
+                        }
+                    }
+                }, {
+                    key: '_doReconnectIfNeeded',
+                    value: function _doReconnectIfNeeded() {
+                        if (this._contentLength == null || this._receivedLength < this._contentLength) {
+                            this._isReconnecting = true;
+                            this._lastTimeBufferSize = 0;
+                            this._internalAbort();
+
+                            var range = {
+                                from: this._totalRange.from + this._receivedLength,
+                                to: -1
+                            };
+                            this._internalOpen(this._dataSource, range, true);
+                        }
+                    }
+                }, {
+                    key: '_msrOnLoad',
+                    value: function _msrOnLoad(e) {
+                        // actually it is onComplete event
+                        this._status = _loader.LoaderStatus.kComplete;
+                        if (this._onComplete) {
+                            this._onComplete(this._totalRange.from, this._totalRange.from + this._receivedLength - 1);
+                        }
+                    }
+                }, {
+                    key: '_msrOnError',
+                    value: function _msrOnError(e) {
+                        this._status = _loader.LoaderStatus.kError;
+                        var type = 0;
+                        var info = null;
+
+                        if (this._contentLength && this._receivedLength < this._contentLength) {
+                            type = _loader.LoaderErrors.EARLY_EOF;
+                            info = { code: -1, msg: 'MSStream meet Early-Eof' };
+                        } else {
+                            type = _loader.LoaderErrors.EARLY_EOF;
+                            info = { code: -1, msg: e.constructor.name + ' ' + e.type };
+                        }
+
+                        if (this._onError) {
+                            this._onError(type, info);
+                        } else {
+                            throw new _exception.RuntimeException(info.msg);
+                        }
+                    }
+                }]);
+
+                return MSStreamLoader;
+            }(_loader.BaseLoader);
+
+            exports.default = MSStreamLoader;
+
+        }, { "../utils/exception.js": 40, "../utils/logger.js": 41, "./loader.js": 24 }], 31: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; };
+
+            var _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); } };
+
+            var _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; }; }();
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _speedSampler = _dereq_('./speed-sampler.js');
+
+            var _speedSampler2 = _interopRequireDefault(_speedSampler);
+
+            var _loader = _dereq_('./loader.js');
+
+            var _exception = _dereq_('../utils/exception.js');
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            function _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; }
+
+            function _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; } /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+
+            // Universal IO Loader, implemented by adding Range header in xhr's request header
+            var RangeLoader = function (_BaseLoader) {
+                _inherits(RangeLoader, _BaseLoader);
+
+                _createClass(RangeLoader, null, [{
+                    key: 'isSupported',
+                    value: function isSupported() {
+                        try {
+                            var xhr = new XMLHttpRequest();
+                            xhr.open('GET', 'https://example.com', true);
+                            xhr.responseType = 'arraybuffer';
+                            return xhr.responseType === 'arraybuffer';
+                        } catch (e) {
+                            _logger2.default.w('RangeLoader', e.message);
+                            return false;
+                        }
+                    }
+                }]);
+
+                function RangeLoader(seekHandler, config) {
+                    _classCallCheck(this, RangeLoader);
+
+                    var _this = _possibleConstructorReturn(this, (RangeLoader.__proto__ || Object.getPrototypeOf(RangeLoader)).call(this, 'xhr-range-loader'));
+
+                    _this.TAG = 'RangeLoader';
+
+                    _this._seekHandler = seekHandler;
+                    _this._config = config;
+                    _this._needStash = false;
+
+                    _this._chunkSizeKBList = [128, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 5120, 6144, 7168, 8192];
+                    _this._currentChunkSizeKB = 384;
+                    _this._currentSpeedNormalized = 0;
+                    _this._zeroSpeedChunkCount = 0;
+
+                    _this._xhr = null;
+                    _this._speedSampler = new _speedSampler2.default();
+
+                    _this._requestAbort = false;
+                    _this._waitForTotalLength = false;
+                    _this._totalLengthReceived = false;
+
+                    _this._currentRequestURL = null;
+                    _this._currentRedirectedURL = null;
+                    _this._currentRequestRange = null;
+                    _this._totalLength = null; // size of the entire file
+                    _this._contentLength = null; // Content-Length of entire request range
+                    _this._receivedLength = 0; // total received bytes
+                    _this._lastTimeLoaded = 0; // received bytes of current request sub-range
+                    return _this;
+                }
+
+                _createClass(RangeLoader, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        if (this.isWorking()) {
+                            this.abort();
+                        }
+                        if (this._xhr) {
+                            this._xhr.onreadystatechange = null;
+                            this._xhr.onprogress = null;
+                            this._xhr.onload = null;
+                            this._xhr.onerror = null;
+                            this._xhr = null;
+                        }
+                        _get(RangeLoader.prototype.__proto__ || Object.getPrototypeOf(RangeLoader.prototype), 'destroy', this).call(this);
+                    }
+                }, {
+                    key: 'open',
+                    value: function open(dataSource, range) {
+                        this._dataSource = dataSource;
+                        this._range = range;
+                        this._status = _loader.LoaderStatus.kConnecting;
+
+                        var useRefTotalLength = false;
+                        if (this._dataSource.filesize != undefined && this._dataSource.filesize !== 0) {
+                            useRefTotalLength = true;
+                            this._totalLength = this._dataSource.filesize;
+                        }
+
+                        if (!this._totalLengthReceived && !useRefTotalLength) {
+                            // We need total filesize
+                            this._waitForTotalLength = true;
+                            this._internalOpen(this._dataSource, { from: 0, to: -1 });
+                        } else {
+                            // We have filesize, start loading
+                            this._openSubRange();
+                        }
+                    }
+                }, {
+                    key: '_openSubRange',
+                    value: function _openSubRange() {
+                        var chunkSize = this._currentChunkSizeKB * 1024;
+
+                        var from = this._range.from + this._receivedLength;
+                        var to = from + chunkSize;
+
+                        if (this._contentLength != null) {
+                            if (to - this._range.from >= this._contentLength) {
+                                to = this._range.from + this._contentLength - 1;
+                            }
+                        }
+
+                        this._currentRequestRange = { from: from, to: to };
+                        this._internalOpen(this._dataSource, this._currentRequestRange);
+                    }
+                }, {
+                    key: '_internalOpen',
+                    value: function _internalOpen(dataSource, range) {
+                        this._lastTimeLoaded = 0;
+
+                        var sourceURL = dataSource.url;
+                        if (this._config.reuseRedirectedURL) {
+                            if (this._currentRedirectedURL != undefined) {
+                                sourceURL = this._currentRedirectedURL;
+                            } else if (dataSource.redirectedURL != undefined) {
+                                sourceURL = dataSource.redirectedURL;
+                            }
+                        }
+
+                        var seekConfig = this._seekHandler.getConfig(sourceURL, range);
+                        this._currentRequestURL = seekConfig.url;
+
+                        var xhr = this._xhr = new XMLHttpRequest();
+                        xhr.open('GET', seekConfig.url, true);
+                        xhr.responseType = 'arraybuffer';
+                        xhr.onreadystatechange = this._onReadyStateChange.bind(this);
+                        xhr.onprogress = this._onProgress.bind(this);
+                        xhr.onload = this._onLoad.bind(this);
+                        xhr.onerror = this._onXhrError.bind(this);
+
+                        if (dataSource.withCredentials) {
+                            xhr.withCredentials = true;
+                        }
+
+                        if (_typeof(seekConfig.headers) === 'object') {
+                            var headers = seekConfig.headers;
+
+                            for (var key in headers) {
+                                if (headers.hasOwnProperty(key)) {
+                                    xhr.setRequestHeader(key, headers[key]);
+                                }
+                            }
+                        }
+
+                        // add additional headers
+                        if (_typeof(this._config.headers) === 'object') {
+                            var _headers = this._config.headers;
+
+                            for (var _key in _headers) {
+                                if (_headers.hasOwnProperty(_key)) {
+                                    xhr.setRequestHeader(_key, _headers[_key]);
+                                }
+                            }
+                        }
+
+                        xhr.send();
+                    }
+                }, {
+                    key: 'abort',
+                    value: function abort() {
+                        this._requestAbort = true;
+                        this._internalAbort();
+                        this._status = _loader.LoaderStatus.kComplete;
+                    }
+                }, {
+                    key: '_internalAbort',
+                    value: function _internalAbort() {
+                        if (this._xhr) {
+                            this._xhr.onreadystatechange = null;
+                            this._xhr.onprogress = null;
+                            this._xhr.onload = null;
+                            this._xhr.onerror = null;
+                            this._xhr.abort();
+                            this._xhr = null;
+                        }
+                    }
+                }, {
+                    key: '_onReadyStateChange',
+                    value: function _onReadyStateChange(e) {
+                        var xhr = e.target;
+
+                        if (xhr.readyState === 2) {
+                            // HEADERS_RECEIVED
+                            if (xhr.responseURL != undefined) {
+                                // if the browser support this property
+                                var redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
+                                if (xhr.responseURL !== this._currentRequestURL && redirectedURL !== this._currentRedirectedURL) {
+                                    this._currentRedirectedURL = redirectedURL;
+                                    if (this._onURLRedirect) {
+                                        this._onURLRedirect(redirectedURL);
+                                    }
+                                }
+                            }
+
+                            if (xhr.status >= 200 && xhr.status <= 299) {
+                                if (this._waitForTotalLength) {
+                                    return;
+                                }
+                                this._status = _loader.LoaderStatus.kBuffering;
+                            } else {
+                                this._status = _loader.LoaderStatus.kError;
+                                if (this._onError) {
+                                    this._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: xhr.status, msg: xhr.statusText });
+                                } else {
+                                    throw new _exception.RuntimeException('RangeLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
+                                }
+                            }
+                        }
+                    }
+                }, {
+                    key: '_onProgress',
+                    value: function _onProgress(e) {
+                        if (this._status === _loader.LoaderStatus.kError) {
+                            // Ignore error response
+                            return;
+                        }
+
+                        if (this._contentLength === null) {
+                            var openNextRange = false;
+
+                            if (this._waitForTotalLength) {
+                                this._waitForTotalLength = false;
+                                this._totalLengthReceived = true;
+                                openNextRange = true;
+
+                                var total = e.total;
+                                this._internalAbort();
+                                if (total != null & total !== 0) {
+                                    this._totalLength = total;
+                                }
+                            }
+
+                            // calculate currrent request range's contentLength
+                            if (this._range.to === -1) {
+                                this._contentLength = this._totalLength - this._range.from;
+                            } else {
+                                // to !== -1
+                                this._contentLength = this._range.to - this._range.from + 1;
+                            }
+
+                            if (openNextRange) {
+                                this._openSubRange();
+                                return;
+                            }
                             if (this._onContentLengthKnown) {
                                 this._onContentLengthKnown(this._contentLength);
                             }
                         }
+
+                        var delta = e.loaded - this._lastTimeLoaded;
+                        this._lastTimeLoaded = e.loaded;
+                        this._speedSampler.addBytes(delta);
                     }
-                } else {
-                    this._status = _loader.LoaderStatus.kError;
-                    if (this._onError) {
-                        this._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: xhr.status, msg: xhr.statusText });
-                    } else {
-                        throw new _exception.RuntimeException('MSStreamLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
-                    }
-                }
-            } else if (xhr.readyState === 3) {
-                // LOADING
-                if (xhr.status >= 200 && xhr.status <= 299) {
-                    this._status = _loader.LoaderStatus.kBuffering;
+                }, {
+                    key: '_normalizeSpeed',
+                    value: function _normalizeSpeed(input) {
+                        var list = this._chunkSizeKBList;
+                        var last = list.length - 1;
+                        var mid = 0;
+                        var lbound = 0;
+                        var ubound = last;
 
-                    var msstream = xhr.response;
-                    this._reader.readAsArrayBuffer(msstream);
-                }
-            }
-        }
-    }, {
-        key: '_xhrOnError',
-        value: function _xhrOnError(e) {
-            this._status = _loader.LoaderStatus.kError;
-            var type = _loader.LoaderErrors.EXCEPTION;
-            var info = { code: -1, msg: e.constructor.name + ' ' + e.type };
+                        if (input < list[0]) {
+                            return list[0];
+                        }
 
-            if (this._onError) {
-                this._onError(type, info);
-            } else {
-                throw new _exception.RuntimeException(info.msg);
-            }
-        }
-    }, {
-        key: '_msrOnProgress',
-        value: function _msrOnProgress(e) {
-            var reader = e.target;
-            var bigbuffer = reader.result;
-            if (bigbuffer == null) {
-                // result may be null, workaround for buggy M$
-                this._doReconnectIfNeeded();
-                return;
-            }
-
-            var slice = bigbuffer.slice(this._lastTimeBufferSize);
-            this._lastTimeBufferSize = bigbuffer.byteLength;
-            var byteStart = this._totalRange.from + this._receivedLength;
-            this._receivedLength += slice.byteLength;
-
-            if (this._onDataArrival) {
-                this._onDataArrival(slice, byteStart, this._receivedLength);
-            }
-
-            if (bigbuffer.byteLength >= this._bufferLimit) {
-                _logger2.default.v(this.TAG, 'MSStream buffer exceeded max size near ' + (byteStart + slice.byteLength) + ', reconnecting...');
-                this._doReconnectIfNeeded();
-            }
-        }
-    }, {
-        key: '_doReconnectIfNeeded',
-        value: function _doReconnectIfNeeded() {
-            if (this._contentLength == null || this._receivedLength < this._contentLength) {
-                this._isReconnecting = true;
-                this._lastTimeBufferSize = 0;
-                this._internalAbort();
-
-                var range = {
-                    from: this._totalRange.from + this._receivedLength,
-                    to: -1
-                };
-                this._internalOpen(this._dataSource, range, true);
-            }
-        }
-    }, {
-        key: '_msrOnLoad',
-        value: function _msrOnLoad(e) {
-            // actually it is onComplete event
-            this._status = _loader.LoaderStatus.kComplete;
-            if (this._onComplete) {
-                this._onComplete(this._totalRange.from, this._totalRange.from + this._receivedLength - 1);
-            }
-        }
-    }, {
-        key: '_msrOnError',
-        value: function _msrOnError(e) {
-            this._status = _loader.LoaderStatus.kError;
-            var type = 0;
-            var info = null;
-
-            if (this._contentLength && this._receivedLength < this._contentLength) {
-                type = _loader.LoaderErrors.EARLY_EOF;
-                info = { code: -1, msg: 'MSStream meet Early-Eof' };
-            } else {
-                type = _loader.LoaderErrors.EARLY_EOF;
-                info = { code: -1, msg: e.constructor.name + ' ' + e.type };
-            }
-
-            if (this._onError) {
-                this._onError(type, info);
-            } else {
-                throw new _exception.RuntimeException(info.msg);
-            }
-        }
-    }]);
-
-    return MSStreamLoader;
-}(_loader.BaseLoader);
-
-exports.default = MSStreamLoader;
-
-},{"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24}],31:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; };
-
-var _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); } };
-
-var _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; }; }();
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _speedSampler = _dereq_('./speed-sampler.js');
-
-var _speedSampler2 = _interopRequireDefault(_speedSampler);
-
-var _loader = _dereq_('./loader.js');
-
-var _exception = _dereq_('../utils/exception.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _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; }
-
-function _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; } /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
-
-// Universal IO Loader, implemented by adding Range header in xhr's request header
-var RangeLoader = function (_BaseLoader) {
-    _inherits(RangeLoader, _BaseLoader);
-
-    _createClass(RangeLoader, null, [{
-        key: 'isSupported',
-        value: function isSupported() {
-            try {
-                var xhr = new XMLHttpRequest();
-                xhr.open('GET', 'https://example.com', true);
-                xhr.responseType = 'arraybuffer';
-                return xhr.responseType === 'arraybuffer';
-            } catch (e) {
-                _logger2.default.w('RangeLoader', e.message);
-                return false;
-            }
-        }
-    }]);
-
-    function RangeLoader(seekHandler, config) {
-        _classCallCheck(this, RangeLoader);
-
-        var _this = _possibleConstructorReturn(this, (RangeLoader.__proto__ || Object.getPrototypeOf(RangeLoader)).call(this, 'xhr-range-loader'));
-
-        _this.TAG = 'RangeLoader';
-
-        _this._seekHandler = seekHandler;
-        _this._config = config;
-        _this._needStash = false;
-
-        _this._chunkSizeKBList = [128, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 5120, 6144, 7168, 8192];
-        _this._currentChunkSizeKB = 384;
-        _this._currentSpeedNormalized = 0;
-        _this._zeroSpeedChunkCount = 0;
-
-        _this._xhr = null;
-        _this._speedSampler = new _speedSampler2.default();
-
-        _this._requestAbort = false;
-        _this._waitForTotalLength = false;
-        _this._totalLengthReceived = false;
-
-        _this._currentRequestURL = null;
-        _this._currentRedirectedURL = null;
-        _this._currentRequestRange = null;
-        _this._totalLength = null; // size of the entire file
-        _this._contentLength = null; // Content-Length of entire request range
-        _this._receivedLength = 0; // total received bytes
-        _this._lastTimeLoaded = 0; // received bytes of current request sub-range
-        return _this;
-    }
-
-    _createClass(RangeLoader, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this.isWorking()) {
-                this.abort();
-            }
-            if (this._xhr) {
-                this._xhr.onreadystatechange = null;
-                this._xhr.onprogress = null;
-                this._xhr.onload = null;
-                this._xhr.onerror = null;
-                this._xhr = null;
-            }
-            _get(RangeLoader.prototype.__proto__ || Object.getPrototypeOf(RangeLoader.prototype), 'destroy', this).call(this);
-        }
-    }, {
-        key: 'open',
-        value: function open(dataSource, range) {
-            this._dataSource = dataSource;
-            this._range = range;
-            this._status = _loader.LoaderStatus.kConnecting;
-
-            var useRefTotalLength = false;
-            if (this._dataSource.filesize != undefined && this._dataSource.filesize !== 0) {
-                useRefTotalLength = true;
-                this._totalLength = this._dataSource.filesize;
-            }
-
-            if (!this._totalLengthReceived && !useRefTotalLength) {
-                // We need total filesize
-                this._waitForTotalLength = true;
-                this._internalOpen(this._dataSource, { from: 0, to: -1 });
-            } else {
-                // We have filesize, start loading
-                this._openSubRange();
-            }
-        }
-    }, {
-        key: '_openSubRange',
-        value: function _openSubRange() {
-            var chunkSize = this._currentChunkSizeKB * 1024;
-
-            var from = this._range.from + this._receivedLength;
-            var to = from + chunkSize;
-
-            if (this._contentLength != null) {
-                if (to - this._range.from >= this._contentLength) {
-                    to = this._range.from + this._contentLength - 1;
-                }
-            }
-
-            this._currentRequestRange = { from: from, to: to };
-            this._internalOpen(this._dataSource, this._currentRequestRange);
-        }
-    }, {
-        key: '_internalOpen',
-        value: function _internalOpen(dataSource, range) {
-            this._lastTimeLoaded = 0;
-
-            var sourceURL = dataSource.url;
-            if (this._config.reuseRedirectedURL) {
-                if (this._currentRedirectedURL != undefined) {
-                    sourceURL = this._currentRedirectedURL;
-                } else if (dataSource.redirectedURL != undefined) {
-                    sourceURL = dataSource.redirectedURL;
-                }
-            }
-
-            var seekConfig = this._seekHandler.getConfig(sourceURL, range);
-            this._currentRequestURL = seekConfig.url;
-
-            var xhr = this._xhr = new XMLHttpRequest();
-            xhr.open('GET', seekConfig.url, true);
-            xhr.responseType = 'arraybuffer';
-            xhr.onreadystatechange = this._onReadyStateChange.bind(this);
-            xhr.onprogress = this._onProgress.bind(this);
-            xhr.onload = this._onLoad.bind(this);
-            xhr.onerror = this._onXhrError.bind(this);
-
-            if (dataSource.withCredentials) {
-                xhr.withCredentials = true;
-            }
-
-            if (_typeof(seekConfig.headers) === 'object') {
-                var headers = seekConfig.headers;
-
-                for (var key in headers) {
-                    if (headers.hasOwnProperty(key)) {
-                        xhr.setRequestHeader(key, headers[key]);
-                    }
-                }
-            }
-
-            // add additional headers
-            if (_typeof(this._config.headers) === 'object') {
-                var _headers = this._config.headers;
-
-                for (var _key in _headers) {
-                    if (_headers.hasOwnProperty(_key)) {
-                        xhr.setRequestHeader(_key, _headers[_key]);
-                    }
-                }
-            }
-
-            xhr.send();
-        }
-    }, {
-        key: 'abort',
-        value: function abort() {
-            this._requestAbort = true;
-            this._internalAbort();
-            this._status = _loader.LoaderStatus.kComplete;
-        }
-    }, {
-        key: '_internalAbort',
-        value: function _internalAbort() {
-            if (this._xhr) {
-                this._xhr.onreadystatechange = null;
-                this._xhr.onprogress = null;
-                this._xhr.onload = null;
-                this._xhr.onerror = null;
-                this._xhr.abort();
-                this._xhr = null;
-            }
-        }
-    }, {
-        key: '_onReadyStateChange',
-        value: function _onReadyStateChange(e) {
-            var xhr = e.target;
-
-            if (xhr.readyState === 2) {
-                // HEADERS_RECEIVED
-                if (xhr.responseURL != undefined) {
-                    // if the browser support this property
-                    var redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
-                    if (xhr.responseURL !== this._currentRequestURL && redirectedURL !== this._currentRedirectedURL) {
-                        this._currentRedirectedURL = redirectedURL;
-                        if (this._onURLRedirect) {
-                            this._onURLRedirect(redirectedURL);
+                        while (lbound <= ubound) {
+                            mid = lbound + Math.floor((ubound - lbound) / 2);
+                            if (mid === last || input >= list[mid] && input < list[mid + 1]) {
+                                return list[mid];
+                            } else if (list[mid] < input) {
+                                lbound = mid + 1;
+                            } else {
+                                ubound = mid - 1;
+                            }
                         }
                     }
-                }
+                }, {
+                    key: '_onLoad',
+                    value: function _onLoad(e) {
+                        if (this._status === _loader.LoaderStatus.kError) {
+                            // Ignore error response
+                            return;
+                        }
 
-                if (xhr.status >= 200 && xhr.status <= 299) {
-                    if (this._waitForTotalLength) {
-                        return;
+                        if (this._waitForTotalLength) {
+                            this._waitForTotalLength = false;
+                            return;
+                        }
+
+                        this._lastTimeLoaded = 0;
+                        var KBps = this._speedSampler.lastSecondKBps;
+                        if (KBps === 0) {
+                            this._zeroSpeedChunkCount++;
+                            if (this._zeroSpeedChunkCount >= 3) {
+                                // Try get currentKBps after 3 chunks
+                                KBps = this._speedSampler.currentKBps;
+                            }
+                        }
+
+                        if (KBps !== 0) {
+                            var normalized = this._normalizeSpeed(KBps);
+                            if (this._currentSpeedNormalized !== normalized) {
+                                this._currentSpeedNormalized = normalized;
+                                this._currentChunkSizeKB = normalized;
+                            }
+                        }
+
+                        var chunk = e.target.response;
+                        var byteStart = this._range.from + this._receivedLength;
+                        this._receivedLength += chunk.byteLength;
+
+                        var reportComplete = false;
+
+                        if (this._contentLength != null && this._receivedLength < this._contentLength) {
+                            // continue load next chunk
+                            this._openSubRange();
+                        } else {
+                            reportComplete = true;
+                        }
+
+                        // dispatch received chunk
+                        if (this._onDataArrival) {
+                            this._onDataArrival(chunk, byteStart, this._receivedLength);
+                        }
+
+                        if (reportComplete) {
+                            this._status = _loader.LoaderStatus.kComplete;
+                            if (this._onComplete) {
+                                this._onComplete(this._range.from, this._range.from + this._receivedLength - 1);
+                            }
+                        }
                     }
-                    this._status = _loader.LoaderStatus.kBuffering;
-                } else {
-                    this._status = _loader.LoaderStatus.kError;
-                    if (this._onError) {
-                        this._onError(_loader.LoaderErrors.HTTP_STATUS_CODE_INVALID, { code: xhr.status, msg: xhr.statusText });
-                    } else {
-                        throw new _exception.RuntimeException('RangeLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
+                }, {
+                    key: '_onXhrError',
+                    value: function _onXhrError(e) {
+                        this._status = _loader.LoaderStatus.kError;
+                        var type = 0;
+                        var info = null;
+
+                        if (this._contentLength && this._receivedLength > 0 && this._receivedLength < this._contentLength) {
+                            type = _loader.LoaderErrors.EARLY_EOF;
+                            info = { code: -1, msg: 'RangeLoader meet Early-Eof' };
+                        } else {
+                            type = _loader.LoaderErrors.EXCEPTION;
+                            info = { code: -1, msg: e.constructor.name + ' ' + e.type };
+                        }
+
+                        if (this._onError) {
+                            this._onError(type, info);
+                        } else {
+                            throw new _exception.RuntimeException(info.msg);
+                        }
                     }
-                }
-            }
-        }
-    }, {
-        key: '_onProgress',
-        value: function _onProgress(e) {
-            if (this._status === _loader.LoaderStatus.kError) {
-                // Ignore error response
-                return;
-            }
-
-            if (this._contentLength === null) {
-                var openNextRange = false;
-
-                if (this._waitForTotalLength) {
-                    this._waitForTotalLength = false;
-                    this._totalLengthReceived = true;
-                    openNextRange = true;
-
-                    var total = e.total;
-                    this._internalAbort();
-                    if (total != null & total !== 0) {
-                        this._totalLength = total;
+                }, {
+                    key: 'currentSpeed',
+                    get: function get() {
+                        return this._speedSampler.lastSecondKBps;
                     }
-                }
+                }]);
 
-                // calculate currrent request range's contentLength
-                if (this._range.to === -1) {
-                    this._contentLength = this._totalLength - this._range.from;
-                } else {
-                    // to !== -1
-                    this._contentLength = this._range.to - this._range.from + 1;
-                }
+                return RangeLoader;
+            }(_loader.BaseLoader);
 
-                if (openNextRange) {
-                    this._openSubRange();
-                    return;
-                }
-                if (this._onContentLengthKnown) {
-                    this._onContentLengthKnown(this._contentLength);
-                }
-            }
+            exports.default = RangeLoader;
 
-            var delta = e.loaded - this._lastTimeLoaded;
-            this._lastTimeLoaded = e.loaded;
-            this._speedSampler.addBytes(delta);
-        }
-    }, {
-        key: '_normalizeSpeed',
-        value: function _normalizeSpeed(input) {
-            var list = this._chunkSizeKBList;
-            var last = list.length - 1;
-            var mid = 0;
-            var lbound = 0;
-            var ubound = last;
+        }, { "../utils/exception.js": 40, "../utils/logger.js": 41, "./loader.js": 24, "./speed-sampler.js": 27 }], 32: [function (_dereq_, module, exports) {
+            'use strict';
 
-            if (input < list[0]) {
-                return list[0];
-            }
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
 
-            while (lbound <= ubound) {
-                mid = lbound + Math.floor((ubound - lbound) / 2);
-                if (mid === last || input >= list[mid] && input < list[mid + 1]) {
-                    return list[mid];
-                } else if (list[mid] < input) {
-                    lbound = mid + 1;
-                } else {
-                    ubound = mid - 1;
-                }
-            }
-        }
-    }, {
-        key: '_onLoad',
-        value: function _onLoad(e) {
-            if (this._status === _loader.LoaderStatus.kError) {
-                // Ignore error response
-                return;
-            }
+            var _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; };
 
-            if (this._waitForTotalLength) {
-                this._waitForTotalLength = false;
-                return;
-            }
-
-            this._lastTimeLoaded = 0;
-            var KBps = this._speedSampler.lastSecondKBps;
-            if (KBps === 0) {
-                this._zeroSpeedChunkCount++;
-                if (this._zeroSpeedChunkCount >= 3) {
-                    // Try get currentKBps after 3 chunks
-                    KBps = this._speedSampler.currentKBps;
-                }
-            }
-
-            if (KBps !== 0) {
-                var normalized = this._normalizeSpeed(KBps);
-                if (this._currentSpeedNormalized !== normalized) {
-                    this._currentSpeedNormalized = normalized;
-                    this._currentChunkSizeKB = normalized;
-                }
-            }
-
-            var chunk = e.target.response;
-            var byteStart = this._range.from + this._receivedLength;
-            this._receivedLength += chunk.byteLength;
-
-            var reportComplete = false;
-
-            if (this._contentLength != null && this._receivedLength < this._contentLength) {
-                // continue load next chunk
-                this._openSubRange();
-            } else {
-                reportComplete = true;
-            }
-
-            // dispatch received chunk
-            if (this._onDataArrival) {
-                this._onDataArrival(chunk, byteStart, this._receivedLength);
-            }
-
-            if (reportComplete) {
-                this._status = _loader.LoaderStatus.kComplete;
-                if (this._onComplete) {
-                    this._onComplete(this._range.from, this._range.from + this._receivedLength - 1);
-                }
-            }
-        }
-    }, {
-        key: '_onXhrError',
-        value: function _onXhrError(e) {
-            this._status = _loader.LoaderStatus.kError;
-            var type = 0;
-            var info = null;
-
-            if (this._contentLength && this._receivedLength > 0 && this._receivedLength < this._contentLength) {
-                type = _loader.LoaderErrors.EARLY_EOF;
-                info = { code: -1, msg: 'RangeLoader meet Early-Eof' };
-            } else {
-                type = _loader.LoaderErrors.EXCEPTION;
-                info = { code: -1, msg: e.constructor.name + ' ' + e.type };
-            }
-
-            if (this._onError) {
-                this._onError(type, info);
-            } else {
-                throw new _exception.RuntimeException(info.msg);
-            }
-        }
-    }, {
-        key: 'currentSpeed',
-        get: function get() {
-            return this._speedSampler.lastSecondKBps;
-        }
-    }]);
-
-    return RangeLoader;
-}(_loader.BaseLoader);
-
-exports.default = RangeLoader;
-
-},{"../utils/exception.js":40,"../utils/logger.js":41,"./loader.js":24,"./speed-sampler.js":27}],32:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; };
-
-var _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; }; }(); /*
+            var _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; }; }(); /*
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * Copyright (C) 2016 Bilibili. All Rights Reserved.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       *
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * @author zheng qian <xqq@xqq.im>
@@ -8882,2665 +8893,675 @@
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * limitations under the License.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       */
 
-var _events = _dereq_('events');
+            var _events = _dereq_('events');
 
-var _events2 = _interopRequireDefault(_events);
+            var _events2 = _interopRequireDefault(_events);
 
-var _logger = _dereq_('../utils/logger.js');
+            var _logger = _dereq_('../utils/logger.js');
 
-var _logger2 = _interopRequireDefault(_logger);
+            var _logger2 = _interopRequireDefault(_logger);
 
-var _browser = _dereq_('../utils/browser.js');
+            var _browser = _dereq_('../utils/browser.js');
 
-var _browser2 = _interopRequireDefault(_browser);
+            var _browser2 = _interopRequireDefault(_browser);
 
-var _playerEvents = _dereq_('./player-events.js');
+            var _playerEvents = _dereq_('./player-events.js');
 
-var _playerEvents2 = _interopRequireDefault(_playerEvents);
+            var _playerEvents2 = _interopRequireDefault(_playerEvents);
 
-var _transmuxer = _dereq_('../core/transmuxer.js');
+            var _transmuxer = _dereq_('../core/transmuxer.js');
 
-var _transmuxer2 = _interopRequireDefault(_transmuxer);
+            var _transmuxer2 = _interopRequireDefault(_transmuxer);
 
-var _transmuxingEvents = _dereq_('../core/transmuxing-events.js');
+            var _transmuxingEvents = _dereq_('../core/transmuxing-events.js');
 
-var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
+            var _transmuxingEvents2 = _interopRequireDefault(_transmuxingEvents);
 
-var _mseController = _dereq_('../core/mse-controller.js');
+            var _mseController = _dereq_('../core/mse-controller.js');
 
-var _mseController2 = _interopRequireDefault(_mseController);
+            var _mseController2 = _interopRequireDefault(_mseController);
 
-var _mseEvents = _dereq_('../core/mse-events.js');
+            var _mseEvents = _dereq_('../core/mse-events.js');
 
-var _mseEvents2 = _interopRequireDefault(_mseEvents);
+            var _mseEvents2 = _interopRequireDefault(_mseEvents);
 
-var _playerErrors = _dereq_('./player-errors.js');
+            var _playerErrors = _dereq_('./player-errors.js');
 
-var _config = _dereq_('../config.js');
+            var _config = _dereq_('../config.js');
 
-var _exception = _dereq_('../utils/exception.js');
+            var _exception = _dereq_('../utils/exception.js');
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var FlvPlayer = function () {
-    function FlvPlayer(mediaDataSource, config) {
-        _classCallCheck(this, FlvPlayer);
+            var FlvPlayer = function () {
+                function FlvPlayer(mediaDataSource, config) {
+                    _classCallCheck(this, FlvPlayer);
 
-        this.TAG = 'FlvPlayer';
-        this._type = 'FlvPlayer';
-        this._emitter = new _events2.default();
+                    this.TAG = 'FlvPlayer';
+                    this._type = 'FlvPlayer';
+                    this._emitter = new _events2.default();
 
-        this._config = (0, _config.createDefaultConfig)();
-        if ((typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object') {
-            Object.assign(this._config, config);
-        }
-
-        if (mediaDataSource.type.toLowerCase() !== 'flv') {
-            throw new _exception.InvalidArgumentException('FlvPlayer requires an flv MediaDataSource input!');
-        }
-
-        if (mediaDataSource.isLive === true) {
-            this._config.isLive = true;
-        }
-
-        this.e = {
-            onvLoadedMetadata: this._onvLoadedMetadata.bind(this),
-            onvSeeking: this._onvSeeking.bind(this),
-            onvCanPlay: this._onvCanPlay.bind(this),
-            onvStalled: this._onvStalled.bind(this),
-            onvProgress: this._onvProgress.bind(this)
-        };
-
-        if (self.performance && self.performance.now) {
-            this._now = self.performance.now.bind(self.performance);
-        } else {
-            this._now = Date.now;
-        }
-
-        this._pendingSeekTime = null; // in seconds
-        this._requestSetTime = false;
-        this._seekpointRecord = null;
-        this._progressChecker = null;
-
-        this._mediaDataSource = mediaDataSource;
-        this._mediaElement = null;
-        this._msectl = null;
-        this._transmuxer = null;
-
-        this._mseSourceOpened = false;
-        this._hasPendingLoad = false;
-        this._receivedCanPlay = false;
-
-        this._mediaInfo = null;
-        this._statisticsInfo = null;
-
-        var chromeNeedIDRFix = _browser2.default.chrome && (_browser2.default.version.major < 50 || _browser2.default.version.major === 50 && _browser2.default.version.build < 2661);
-        this._alwaysSeekKeyframe = chromeNeedIDRFix || _browser2.default.msedge || _browser2.default.msie ? true : false;
-
-        if (this._alwaysSeekKeyframe) {
-            this._config.accurateSeek = false;
-        }
-    }
-
-    _createClass(FlvPlayer, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this._progressChecker != null) {
-                window.clearInterval(this._progressChecker);
-                this._progressChecker = null;
-            }
-            if (this._transmuxer) {
-                this.unload();
-            }
-            if (this._mediaElement) {
-                this.detachMediaElement();
-            }
-            this.e = null;
-            this._mediaDataSource = null;
-
-            this._emitter.removeAllListeners();
-            this._emitter = null;
-        }
-    }, {
-        key: 'on',
-        value: function on(event, listener) {
-            var _this = this;
-
-            if (event === _playerEvents2.default.MEDIA_INFO) {
-                if (this._mediaInfo != null) {
-                    Promise.resolve().then(function () {
-                        _this._emitter.emit(_playerEvents2.default.MEDIA_INFO, _this.mediaInfo);
-                    });
-                }
-            } else if (event === _playerEvents2.default.STATISTICS_INFO) {
-                if (this._statisticsInfo != null) {
-                    Promise.resolve().then(function () {
-                        _this._emitter.emit(_playerEvents2.default.STATISTICS_INFO, _this.statisticsInfo);
-                    });
-                }
-            }
-            this._emitter.addListener(event, listener);
-        }
-    }, {
-        key: 'off',
-        value: function off(event, listener) {
-            this._emitter.removeListener(event, listener);
-        }
-    }, {
-        key: 'attachMediaElement',
-        value: function attachMediaElement(mediaElement) {
-            var _this2 = this;
-
-            this._mediaElement = mediaElement;
-            mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata);
-            mediaElement.addEventListener('seeking', this.e.onvSeeking);
-            mediaElement.addEventListener('canplay', this.e.onvCanPlay);
-            mediaElement.addEventListener('stalled', this.e.onvStalled);
-            mediaElement.addEventListener('progress', this.e.onvProgress);
-
-            this._msectl = new _mseController2.default(this._config);
-
-            this._msectl.on(_mseEvents2.default.UPDATE_END, this._onmseUpdateEnd.bind(this));
-            this._msectl.on(_mseEvents2.default.BUFFER_FULL, this._onmseBufferFull.bind(this));
-            this._msectl.on(_mseEvents2.default.SOURCE_OPEN, function () {
-                _this2._mseSourceOpened = true;
-                if (_this2._hasPendingLoad) {
-                    _this2._hasPendingLoad = false;
-                    _this2.load();
-                }
-            });
-            this._msectl.on(_mseEvents2.default.ERROR, function (info) {
-                _this2._emitter.emit(_playerEvents2.default.ERROR, _playerErrors.ErrorTypes.MEDIA_ERROR, _playerErrors.ErrorDetails.MEDIA_MSE_ERROR, info);
-            });
-
-            this._msectl.attachMediaElement(mediaElement);
-
-            if (this._pendingSeekTime != null) {
-                try {
-                    mediaElement.currentTime = this._pendingSeekTime;
-                    this._pendingSeekTime = null;
-                } catch (e) {
-                    // IE11 may throw InvalidStateError if readyState === 0
-                    // We can defer set currentTime operation after loadedmetadata
-                }
-            }
-        }
-    }, {
-        key: 'detachMediaElement',
-        value: function detachMediaElement() {
-            if (this._mediaElement) {
-                this._msectl.detachMediaElement();
-                this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
-                this._mediaElement.removeEventListener('seeking', this.e.onvSeeking);
-                this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay);
-                this._mediaElement.removeEventListener('stalled', this.e.onvStalled);
-                this._mediaElement.removeEventListener('progress', this.e.onvProgress);
-                this._mediaElement = null;
-            }
-            if (this._msectl) {
-                this._msectl.destroy();
-                this._msectl = null;
-            }
-        }
-    }, {
-        key: 'load',
-        value: function load() {
-            var _this3 = this;
-
-            if (!this._mediaElement) {
-                throw new _exception.IllegalStateException('HTMLMediaElement must be attached before load()!');
-            }
-            if (this._transmuxer) {
-                throw new _exception.IllegalStateException('FlvPlayer.load() has been called, please call unload() first!');
-            }
-            if (this._hasPendingLoad) {
-                return;
-            }
-
-            if (this._config.deferLoadAfterSourceOpen && this._mseSourceOpened === false) {
-                this._hasPendingLoad = true;
-                return;
-            }
-
-            if (this._mediaElement.readyState > 0) {
-                this._requestSetTime = true;
-                // IE11 may throw InvalidStateError if readyState === 0
-                this._mediaElement.currentTime = 0;
-            }
-
-            this._transmuxer = new _transmuxer2.default(this._mediaDataSource, this._config);
-
-            this._transmuxer.on(_transmuxingEvents2.default.INIT_SEGMENT, function (type, is) {
-                _this3._msectl.appendInitSegment(is);
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.MEDIA_SEGMENT, function (type, ms) {
-                _this3._msectl.appendMediaSegment(ms);
-
-                // lazyLoad check
-                if (_this3._config.lazyLoad && !_this3._config.isLive) {
-                    var currentTime = _this3._mediaElement.currentTime;
-                    if (ms.info.endDts >= (currentTime + _this3._config.lazyLoadMaxDuration) * 1000) {
-                        if (_this3._progressChecker == null) {
-                            _logger2.default.v(_this3.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
-                            _this3._suspendTransmuxer();
-                        }
+                    this._config = (0, _config.createDefaultConfig)();
+                    if ((typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object') {
+                        Object.assign(this._config, config);
                     }
-                }
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.LOADING_COMPLETE, function () {
-                _this3._msectl.endOfStream();
-                _this3._emitter.emit(_playerEvents2.default.LOADING_COMPLETE);
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.RECOVERED_EARLY_EOF, function () {
-                _this3._emitter.emit(_playerEvents2.default.RECOVERED_EARLY_EOF);
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.IO_ERROR, function (detail, info) {
-                _this3._emitter.emit(_playerEvents2.default.ERROR, _playerErrors.ErrorTypes.NETWORK_ERROR, detail, info);
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.DEMUX_ERROR, function (detail, info) {
-                _this3._emitter.emit(_playerEvents2.default.ERROR, _playerErrors.ErrorTypes.MEDIA_ERROR, detail, { code: -1, msg: info });
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.MEDIA_INFO, function (mediaInfo) {
-                _this3._mediaInfo = mediaInfo;
-                _this3._emitter.emit(_playerEvents2.default.MEDIA_INFO, Object.assign({}, mediaInfo));
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.METADATA_ARRIVED, function (metadata) {
-                _this3._emitter.emit(_playerEvents2.default.METADATA_ARRIVED, metadata);
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, function (data) {
-                _this3._emitter.emit(_playerEvents2.default.SCRIPTDATA_ARRIVED, data);
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.STATISTICS_INFO, function (statInfo) {
-                _this3._statisticsInfo = _this3._fillStatisticsInfo(statInfo);
-                _this3._emitter.emit(_playerEvents2.default.STATISTICS_INFO, Object.assign({}, _this3._statisticsInfo));
-            });
-            this._transmuxer.on(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, function (milliseconds) {
-                if (_this3._mediaElement && !_this3._config.accurateSeek) {
-                    _this3._requestSetTime = true;
-                    _this3._mediaElement.currentTime = milliseconds / 1000;
-                }
-            });
 
-            this._transmuxer.open();
-        }
-    }, {
-        key: 'unload',
-        value: function unload() {
-            if (this._mediaElement) {
-                this._mediaElement.pause();
-            }
-            if (this._msectl) {
-                this._msectl.seek(0);
-            }
-            if (this._transmuxer) {
-                this._transmuxer.close();
-                this._transmuxer.destroy();
-                this._transmuxer = null;
-            }
-        }
-    }, {
-        key: 'play',
-        value: function play() {
-            return this._mediaElement.play();
-        }
-    }, {
-        key: 'pause',
-        value: function pause() {
-            this._mediaElement.pause();
-        }
-    }, {
-        key: '_fillStatisticsInfo',
-        value: function _fillStatisticsInfo(statInfo) {
-            statInfo.playerType = this._type;
-
-            if (!(this._mediaElement instanceof HTMLVideoElement)) {
-                return statInfo;
-            }
-
-            var hasQualityInfo = true;
-            var decoded = 0;
-            var dropped = 0;
-
-            if (this._mediaElement.getVideoPlaybackQuality) {
-                var quality = this._mediaElement.getVideoPlaybackQuality();
-                decoded = quality.totalVideoFrames;
-                dropped = quality.droppedVideoFrames;
-            } else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
-                decoded = this._mediaElement.webkitDecodedFrameCount;
-                dropped = this._mediaElement.webkitDroppedFrameCount;
-            } else {
-                hasQualityInfo = false;
-            }
-
-            if (hasQualityInfo) {
-                statInfo.decodedFrames = decoded;
-                statInfo.droppedFrames = dropped;
-            }
-
-            return statInfo;
-        }
-    }, {
-        key: '_onmseUpdateEnd',
-        value: function _onmseUpdateEnd() {
-            if (!this._config.lazyLoad || this._config.isLive) {
-                return;
-            }
-
-            var buffered = this._mediaElement.buffered;
-            var currentTime = this._mediaElement.currentTime;
-            var currentRangeStart = 0;
-            var currentRangeEnd = 0;
-
-            for (var i = 0; i < buffered.length; i++) {
-                var start = buffered.start(i);
-                var end = buffered.end(i);
-                if (start <= currentTime && currentTime < end) {
-                    currentRangeStart = start;
-                    currentRangeEnd = end;
-                    break;
-                }
-            }
-
-            if (currentRangeEnd >= currentTime + this._config.lazyLoadMaxDuration && this._progressChecker == null) {
-                _logger2.default.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
-                this._suspendTransmuxer();
-            }
-        }
-    }, {
-        key: '_onmseBufferFull',
-        value: function _onmseBufferFull() {
-            _logger2.default.v(this.TAG, 'MSE SourceBuffer is full, suspend transmuxing task');
-            if (this._progressChecker == null) {
-                this._suspendTransmuxer();
-            }
-        }
-    }, {
-        key: '_suspendTransmuxer',
-        value: function _suspendTransmuxer() {
-            if (this._transmuxer) {
-                this._transmuxer.pause();
-
-                if (this._progressChecker == null) {
-                    this._progressChecker = window.setInterval(this._checkProgressAndResume.bind(this), 1000);
-                }
-            }
-        }
-    }, {
-        key: '_checkProgressAndResume',
-        value: function _checkProgressAndResume() {
-            var currentTime = this._mediaElement.currentTime;
-            var buffered = this._mediaElement.buffered;
-
-            var needResume = false;
-
-            for (var i = 0; i < buffered.length; i++) {
-                var from = buffered.start(i);
-                var to = buffered.end(i);
-                if (currentTime >= from && currentTime < to) {
-                    if (currentTime >= to - this._config.lazyLoadRecoverDuration) {
-                        needResume = true;
+                    if (mediaDataSource.type.toLowerCase() !== 'flv') {
+                        throw new _exception.InvalidArgumentException('FlvPlayer requires an flv MediaDataSource input!');
                     }
-                    break;
-                }
-            }
 
-            if (needResume) {
-                window.clearInterval(this._progressChecker);
-                this._progressChecker = null;
-                if (needResume) {
-                    _logger2.default.v(this.TAG, 'Continue loading from paused position');
-                    this._transmuxer.resume();
-                }
-            }
-        }
-    }, {
-        key: '_isTimepointBuffered',
-        value: function _isTimepointBuffered(seconds) {
-            var buffered = this._mediaElement.buffered;
+                    if (mediaDataSource.isLive === true) {
+                        this._config.isLive = true;
+                    }
 
-            for (var i = 0; i < buffered.length; i++) {
-                var from = buffered.start(i);
-                var to = buffered.end(i);
-                if (seconds >= from && seconds < to) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }, {
-        key: '_internalSeek',
-        value: function _internalSeek(seconds) {
-            var directSeek = this._isTimepointBuffered(seconds);
+                    this.e = {
+                        onvLoadedMetadata: this._onvLoadedMetadata.bind(this),
+                        onvSeeking: this._onvSeeking.bind(this),
+                        onvCanPlay: this._onvCanPlay.bind(this),
+                        onvStalled: this._onvStalled.bind(this),
+                        onvProgress: this._onvProgress.bind(this)
+                    };
 
-            var directSeekBegin = false;
-            var directSeekBeginTime = 0;
-
-            if (seconds < 1.0 && this._mediaElement.buffered.length > 0) {
-                var videoBeginTime = this._mediaElement.buffered.start(0);
-                if (videoBeginTime < 1.0 && seconds < videoBeginTime || _browser2.default.safari) {
-                    directSeekBegin = true;
-                    // also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
-                    directSeekBeginTime = _browser2.default.safari ? 0.1 : videoBeginTime;
-                }
-            }
-
-            if (directSeekBegin) {
-                // seek to video begin, set currentTime directly if beginPTS buffered
-                this._requestSetTime = true;
-                this._mediaElement.currentTime = directSeekBeginTime;
-            } else if (directSeek) {
-                // buffered position
-                if (!this._alwaysSeekKeyframe) {
-                    this._requestSetTime = true;
-                    this._mediaElement.currentTime = seconds;
-                } else {
-                    var idr = this._msectl.getNearestKeyframe(Math.floor(seconds * 1000));
-                    this._requestSetTime = true;
-                    if (idr != null) {
-                        this._mediaElement.currentTime = idr.dts / 1000;
+                    if (self.performance && self.performance.now) {
+                        this._now = self.performance.now.bind(self.performance);
                     } else {
-                        this._mediaElement.currentTime = seconds;
+                        this._now = Date.now;
+                    }
+
+                    this._pendingSeekTime = null; // in seconds
+                    this._requestSetTime = false;
+                    this._seekpointRecord = null;
+                    this._progressChecker = null;
+
+                    this._mediaDataSource = mediaDataSource;
+                    this._mediaElement = null;
+                    this._msectl = null;
+                    this._transmuxer = null;
+
+                    this._mseSourceOpened = false;
+                    this._hasPendingLoad = false;
+                    this._receivedCanPlay = false;
+
+                    this._mediaInfo = null;
+                    this._statisticsInfo = null;
+
+                    var chromeNeedIDRFix = _browser2.default.chrome && (_browser2.default.version.major < 50 || _browser2.default.version.major === 50 && _browser2.default.version.build < 2661);
+                    this._alwaysSeekKeyframe = chromeNeedIDRFix || _browser2.default.msedge || _browser2.default.msie ? true : false;
+
+                    if (this._alwaysSeekKeyframe) {
+                        this._config.accurateSeek = false;
                     }
                 }
-                if (this._progressChecker != null) {
-                    this._checkProgressAndResume();
-                }
-            } else {
-                if (this._progressChecker != null) {
-                    window.clearInterval(this._progressChecker);
-                    this._progressChecker = null;
-                }
-                this._msectl.seek(seconds);
-                this._transmuxer.seek(Math.floor(seconds * 1000)); // in milliseconds
-                // no need to set mediaElement.currentTime if non-accurateSeek,
-                // just wait for the recommend_seekpoint callback
-                if (this._config.accurateSeek) {
-                    this._requestSetTime = true;
-                    this._mediaElement.currentTime = seconds;
-                }
-            }
-        }
-    }, {
-        key: '_checkAndApplyUnbufferedSeekpoint',
-        value: function _checkAndApplyUnbufferedSeekpoint() {
-            if (this._seekpointRecord) {
-                if (this._seekpointRecord.recordTime <= this._now() - 100) {
-                    var target = this._mediaElement.currentTime;
-                    this._seekpointRecord = null;
-                    if (!this._isTimepointBuffered(target)) {
+
+                _createClass(FlvPlayer, [{
+                    key: 'destroy',
+                    value: function destroy() {
                         if (this._progressChecker != null) {
-                            window.clearTimeout(this._progressChecker);
+                            window.clearInterval(this._progressChecker);
                             this._progressChecker = null;
                         }
-                        // .currentTime is consists with .buffered timestamp
-                        // Chrome/Edge use DTS, while FireFox/Safari use PTS
-                        this._msectl.seek(target);
-                        this._transmuxer.seek(Math.floor(target * 1000));
-                        // set currentTime if accurateSeek, or wait for recommend_seekpoint callback
-                        if (this._config.accurateSeek) {
+                        if (this._transmuxer) {
+                            this.unload();
+                        }
+                        if (this._mediaElement) {
+                            this.detachMediaElement();
+                        }
+                        this.e = null;
+                        this._mediaDataSource = null;
+
+                        this._emitter.removeAllListeners();
+                        this._emitter = null;
+                    }
+                }, {
+                    key: 'on',
+                    value: function on(event, listener) {
+                        var _this = this;
+
+                        if (event === _playerEvents2.default.MEDIA_INFO) {
+                            if (this._mediaInfo != null) {
+                                Promise.resolve().then(function () {
+                                    _this._emitter.emit(_playerEvents2.default.MEDIA_INFO, _this.mediaInfo);
+                                });
+                            }
+                        } else if (event === _playerEvents2.default.STATISTICS_INFO) {
+                            if (this._statisticsInfo != null) {
+                                Promise.resolve().then(function () {
+                                    _this._emitter.emit(_playerEvents2.default.STATISTICS_INFO, _this.statisticsInfo);
+                                });
+                            }
+                        }
+                        this._emitter.addListener(event, listener);
+                    }
+                }, {
+                    key: 'off',
+                    value: function off(event, listener) {
+                        this._emitter.removeListener(event, listener);
+                    }
+                }, {
+                    key: 'attachMediaElement',
+                    value: function attachMediaElement(mediaElement) {
+                        var _this2 = this;
+
+                        this._mediaElement = mediaElement;
+                        mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata);
+                        mediaElement.addEventListener('seeking', this.e.onvSeeking);
+                        mediaElement.addEventListener('canplay', this.e.onvCanPlay);
+                        mediaElement.addEventListener('stalled', this.e.onvStalled);
+                        mediaElement.addEventListener('progress', this.e.onvProgress);
+
+                        this._msectl = new _mseController2.default(this._config);
+
+                        this._msectl.on(_mseEvents2.default.UPDATE_END, this._onmseUpdateEnd.bind(this));
+                        this._msectl.on(_mseEvents2.default.BUFFER_FULL, this._onmseBufferFull.bind(this));
+                        this._msectl.on(_mseEvents2.default.SOURCE_OPEN, function () {
+                            _this2._mseSourceOpened = true;
+                            if (_this2._hasPendingLoad) {
+                                _this2._hasPendingLoad = false;
+                                _this2.load();
+                            }
+                        });
+                        this._msectl.on(_mseEvents2.default.ERROR, function (info) {
+                            _this2._emitter.emit(_playerEvents2.default.ERROR, _playerErrors.ErrorTypes.MEDIA_ERROR, _playerErrors.ErrorDetails.MEDIA_MSE_ERROR, info);
+                        });
+
+                        this._msectl.attachMediaElement(mediaElement);
+
+                        if (this._pendingSeekTime != null) {
+                            try {
+                                mediaElement.currentTime = this._pendingSeekTime;
+                                this._pendingSeekTime = null;
+                            } catch (e) {
+                                // IE11 may throw InvalidStateError if readyState === 0
+                                // We can defer set currentTime operation after loadedmetadata
+                            }
+                        }
+                    }
+                }, {
+                    key: 'detachMediaElement',
+                    value: function detachMediaElement() {
+                        if (this._mediaElement) {
+                            this._msectl.detachMediaElement();
+                            this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
+                            this._mediaElement.removeEventListener('seeking', this.e.onvSeeking);
+                            this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay);
+                            this._mediaElement.removeEventListener('stalled', this.e.onvStalled);
+                            this._mediaElement.removeEventListener('progress', this.e.onvProgress);
+                            this._mediaElement = null;
+                        }
+                        if (this._msectl) {
+                            this._msectl.destroy();
+                            this._msectl = null;
+                        }
+                    }
+                }, {
+                    key: 'load',
+                    value: function load() {
+                        var _this3 = this;
+
+                        if (!this._mediaElement) {
+                            throw new _exception.IllegalStateException('HTMLMediaElement must be attached before load()!');
+                        }
+                        if (this._transmuxer) {
+                            throw new _exception.IllegalStateException('FlvPlayer.load() has been called, please call unload() first!');
+                        }
+                        if (this._hasPendingLoad) {
+                            return;
+                        }
+
+                        if (this._config.deferLoadAfterSourceOpen && this._mseSourceOpened === false) {
+                            this._hasPendingLoad = true;
+                            return;
+                        }
+
+                        if (this._mediaElement.readyState > 0) {
                             this._requestSetTime = true;
-                            this._mediaElement.currentTime = target;
+                            // IE11 may throw InvalidStateError if readyState === 0
+                            this._mediaElement.currentTime = 0;
                         }
-                    }
-                } else {
-                    window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50);
-                }
-            }
-        }
-    }, {
-        key: '_checkAndResumeStuckPlayback',
-        value: function _checkAndResumeStuckPlayback(stalled) {
-            var media = this._mediaElement;
-            if (stalled || !this._receivedCanPlay || media.readyState < 2) {
-                // HAVE_CURRENT_DATA
-                var buffered = media.buffered;
-                if (buffered.length > 0 && media.currentTime < buffered.start(0)) {
-                    _logger2.default.w(this.TAG, 'Playback seems stuck at ' + media.currentTime + ', seek to ' + buffered.start(0));
-                    this._requestSetTime = true;
-                    this._mediaElement.currentTime = buffered.start(0);
-                    this._mediaElement.removeEventListener('progress', this.e.onvProgress);
-                }
-            } else {
-                // Playback didn't stuck, remove progress event listener
-                this._mediaElement.removeEventListener('progress', this.e.onvProgress);
-            }
-        }
-    }, {
-        key: '_onvLoadedMetadata',
-        value: function _onvLoadedMetadata(e) {
-            if (this._pendingSeekTime != null) {
-                this._mediaElement.currentTime = this._pendingSeekTime;
-                this._pendingSeekTime = null;
-            }
-        }
-    }, {
-        key: '_onvSeeking',
-        value: function _onvSeeking(e) {
-            // handle seeking request from browser's progress bar
-            var target = this._mediaElement.currentTime;
-            var buffered = this._mediaElement.buffered;
 
-            if (this._requestSetTime) {
-                this._requestSetTime = false;
-                return;
-            }
+                        this._transmuxer = new _transmuxer2.default(this._mediaDataSource, this._config);
 
-            if (target < 1.0 && buffered.length > 0) {
-                // seek to video begin, set currentTime directly if beginPTS buffered
-                var videoBeginTime = buffered.start(0);
-                if (videoBeginTime < 1.0 && target < videoBeginTime || _browser2.default.safari) {
-                    this._requestSetTime = true;
-                    // also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
-                    this._mediaElement.currentTime = _browser2.default.safari ? 0.1 : videoBeginTime;
-                    return;
-                }
-            }
+                        this._transmuxer.on(_transmuxingEvents2.default.INIT_SEGMENT, function (type, is) {
+                            _this3._msectl.appendInitSegment(is);
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.MEDIA_SEGMENT, function (type, ms) {
+                            _this3._msectl.appendMediaSegment(ms);
 
-            if (this._isTimepointBuffered(target)) {
-                if (this._alwaysSeekKeyframe) {
-                    var idr = this._msectl.getNearestKeyframe(Math.floor(target * 1000));
-                    if (idr != null) {
-                        this._requestSetTime = true;
-                        this._mediaElement.currentTime = idr.dts / 1000;
-                    }
-                }
-                if (this._progressChecker != null) {
-                    this._checkProgressAndResume();
-                }
-                return;
-            }
-
-            this._seekpointRecord = {
-                seekPoint: target,
-                recordTime: this._now()
-            };
-            window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50);
-        }
-    }, {
-        key: '_onvCanPlay',
-        value: function _onvCanPlay(e) {
-            this._receivedCanPlay = true;
-            this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay);
-        }
-    }, {
-        key: '_onvStalled',
-        value: function _onvStalled(e) {
-            this._checkAndResumeStuckPlayback(true);
-        }
-    }, {
-        key: '_onvProgress',
-        value: function _onvProgress(e) {
-            this._checkAndResumeStuckPlayback();
-        }
-    }, {
-        key: 'type',
-        get: function get() {
-            return this._type;
-        }
-    }, {
-        key: 'buffered',
-        get: function get() {
-            return this._mediaElement.buffered;
-        }
-    }, {
-        key: 'duration',
-        get: function get() {
-            return this._mediaElement.duration;
-        }
-    }, {
-        key: 'volume',
-        get: function get() {
-            return this._mediaElement.volume;
-        },
-        set: function set(value) {
-            this._mediaElement.volume = value;
-        }
-    }, {
-        key: 'muted',
-        get: function get() {
-            return this._mediaElement.muted;
-        },
-        set: function set(muted) {
-            this._mediaElement.muted = muted;
-        }
-    }, {
-        key: 'currentTime',
-        get: function get() {
-            if (this._mediaElement) {
-                return this._mediaElement.currentTime;
-            }
-            return 0;
-        },
-        set: function set(seconds) {
-            if (this._mediaElement) {
-                this._internalSeek(seconds);
-            } else {
-                this._pendingSeekTime = seconds;
-            }
-        }
-    }, {
-        key: 'mediaInfo',
-        get: function get() {
-            return Object.assign({}, this._mediaInfo);
-        }
-    }, {
-        key: 'statisticsInfo',
-        get: function get() {
-            if (this._statisticsInfo == null) {
-                this._statisticsInfo = {};
-            }
-            this._statisticsInfo = this._fillStatisticsInfo(this._statisticsInfo);
-            return Object.assign({}, this._statisticsInfo);
-        }
-    }]);
-
-    return FlvPlayer;
-}();
-
-exports.default = FlvPlayer;
-
-},{"../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){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; };
-
-var _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; }; }(); /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
-
-var _events = _dereq_('events');
-
-var _events2 = _interopRequireDefault(_events);
-
-var _playerEvents = _dereq_('./player-events.js');
-
-var _playerEvents2 = _interopRequireDefault(_playerEvents);
-
-var _config = _dereq_('../config.js');
-
-var _exception = _dereq_('../utils/exception.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-// Player wrapper for browser's native player (HTMLVideoElement) without MediaSource src. 
-var NativePlayer = function () {
-    function NativePlayer(mediaDataSource, config) {
-        _classCallCheck(this, NativePlayer);
-
-        this.TAG = 'NativePlayer';
-        this._type = 'NativePlayer';
-        this._emitter = new _events2.default();
-
-        this._config = (0, _config.createDefaultConfig)();
-        if ((typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object') {
-            Object.assign(this._config, config);
-        }
-
-        if (mediaDataSource.type.toLowerCase() === 'flv') {
-            throw new _exception.InvalidArgumentException('NativePlayer does\'t support flv MediaDataSource input!');
-        }
-        if (mediaDataSource.hasOwnProperty('segments')) {
-            throw new _exception.InvalidArgumentException('NativePlayer(' + mediaDataSource.type + ') doesn\'t support multipart playback!');
-        }
-
-        this.e = {
-            onvLoadedMetadata: this._onvLoadedMetadata.bind(this)
-        };
-
-        this._pendingSeekTime = null;
-        this._statisticsReporter = null;
-
-        this._mediaDataSource = mediaDataSource;
-        this._mediaElement = null;
-    }
-
-    _createClass(NativePlayer, [{
-        key: 'destroy',
-        value: function destroy() {
-            if (this._mediaElement) {
-                this.unload();
-                this.detachMediaElement();
-            }
-            this.e = null;
-            this._mediaDataSource = null;
-            this._emitter.removeAllListeners();
-            this._emitter = null;
-        }
-    }, {
-        key: 'on',
-        value: function on(event, listener) {
-            var _this = this;
-
-            if (event === _playerEvents2.default.MEDIA_INFO) {
-                if (this._mediaElement != null && this._mediaElement.readyState !== 0) {
-                    // HAVE_NOTHING
-                    Promise.resolve().then(function () {
-                        _this._emitter.emit(_playerEvents2.default.MEDIA_INFO, _this.mediaInfo);
-                    });
-                }
-            } else if (event === _playerEvents2.default.STATISTICS_INFO) {
-                if (this._mediaElement != null && this._mediaElement.readyState !== 0) {
-                    Promise.resolve().then(function () {
-                        _this._emitter.emit(_playerEvents2.default.STATISTICS_INFO, _this.statisticsInfo);
-                    });
-                }
-            }
-            this._emitter.addListener(event, listener);
-        }
-    }, {
-        key: 'off',
-        value: function off(event, listener) {
-            this._emitter.removeListener(event, listener);
-        }
-    }, {
-        key: 'attachMediaElement',
-        value: function attachMediaElement(mediaElement) {
-            this._mediaElement = mediaElement;
-            mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata);
-
-            if (this._pendingSeekTime != null) {
-                try {
-                    mediaElement.currentTime = this._pendingSeekTime;
-                    this._pendingSeekTime = null;
-                } catch (e) {
-                    // IE11 may throw InvalidStateError if readyState === 0
-                    // Defer set currentTime operation after loadedmetadata
-                }
-            }
-        }
-    }, {
-        key: 'detachMediaElement',
-        value: function detachMediaElement() {
-            if (this._mediaElement) {
-                this._mediaElement.src = '';
-                this._mediaElement.removeAttribute('src');
-                this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
-                this._mediaElement = null;
-            }
-            if (this._statisticsReporter != null) {
-                window.clearInterval(this._statisticsReporter);
-                this._statisticsReporter = null;
-            }
-        }
-    }, {
-        key: 'load',
-        value: function load() {
-            if (!this._mediaElement) {
-                throw new _exception.IllegalStateException('HTMLMediaElement must be attached before load()!');
-            }
-            this._mediaElement.src = this._mediaDataSource.url;
-
-            if (this._mediaElement.readyState > 0) {
-                this._mediaElement.currentTime = 0;
-            }
-
-            this._mediaElement.preload = 'auto';
-            this._mediaElement.load();
-            this._statisticsReporter = window.setInterval(this._reportStatisticsInfo.bind(this), this._config.statisticsInfoReportInterval);
-        }
-    }, {
-        key: 'unload',
-        value: function unload() {
-            if (this._mediaElement) {
-                this._mediaElement.src = '';
-                this._mediaElement.removeAttribute('src');
-            }
-            if (this._statisticsReporter != null) {
-                window.clearInterval(this._statisticsReporter);
-                this._statisticsReporter = null;
-            }
-        }
-    }, {
-        key: 'play',
-        value: function play() {
-            return this._mediaElement.play();
-        }
-    }, {
-        key: 'pause',
-        value: function pause() {
-            this._mediaElement.pause();
-        }
-    }, {
-        key: '_onvLoadedMetadata',
-        value: function _onvLoadedMetadata(e) {
-            if (this._pendingSeekTime != null) {
-                this._mediaElement.currentTime = this._pendingSeekTime;
-                this._pendingSeekTime = null;
-            }
-            this._emitter.emit(_playerEvents2.default.MEDIA_INFO, this.mediaInfo);
-        }
-    }, {
-        key: '_reportStatisticsInfo',
-        value: function _reportStatisticsInfo() {
-            this._emitter.emit(_playerEvents2.default.STATISTICS_INFO, this.statisticsInfo);
-        }
-    }, {
-        key: 'type',
-        get: function get() {
-            return this._type;
-        }
-    }, {
-        key: 'buffered',
-        get: function get() {
-            return this._mediaElement.buffered;
-        }
-    }, {
-        key: 'duration',
-        get: function get() {
-            return this._mediaElement.duration;
-        }
-    }, {
-        key: 'volume',
-        get: function get() {
-            return this._mediaElement.volume;
-        },
-        set: function set(value) {
-            this._mediaElement.volume = value;
-        }
-    }, {
-        key: 'muted',
-        get: function get() {
-            return this._mediaElement.muted;
-        },
-        set: function set(muted) {
-            this._mediaElement.muted = muted;
-        }
-    }, {
-        key: 'currentTime',
-        get: function get() {
-            if (this._mediaElement) {
-                return this._mediaElement.currentTime;
-            }
-            return 0;
-        },
-        set: function set(seconds) {
-            if (this._mediaElement) {
-                this._mediaElement.currentTime = seconds;
-            } else {
-                this._pendingSeekTime = seconds;
-            }
-        }
-    }, {
-        key: 'mediaInfo',
-        get: function get() {
-            var mediaPrefix = this._mediaElement instanceof HTMLAudioElement ? 'audio/' : 'video/';
-            var info = {
-                mimeType: mediaPrefix + this._mediaDataSource.type
-            };
-            if (this._mediaElement) {
-                info.duration = Math.floor(this._mediaElement.duration * 1000);
-                if (this._mediaElement instanceof HTMLVideoElement) {
-                    info.width = this._mediaElement.videoWidth;
-                    info.height = this._mediaElement.videoHeight;
-                }
-            }
-            return info;
-        }
-    }, {
-        key: 'statisticsInfo',
-        get: function get() {
-            var info = {
-                playerType: this._type,
-                url: this._mediaDataSource.url
-            };
-
-            if (!(this._mediaElement instanceof HTMLVideoElement)) {
-                return info;
-            }
-
-            var hasQualityInfo = true;
-            var decoded = 0;
-            var dropped = 0;
-
-            if (this._mediaElement.getVideoPlaybackQuality) {
-                var quality = this._mediaElement.getVideoPlaybackQuality();
-                decoded = quality.totalVideoFrames;
-                dropped = quality.droppedVideoFrames;
-            } else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
-                decoded = this._mediaElement.webkitDecodedFrameCount;
-                dropped = this._mediaElement.webkitDroppedFrameCount;
-            } else {
-                hasQualityInfo = false;
-            }
-
-            if (hasQualityInfo) {
-                info.decodedFrames = decoded;
-                info.droppedFrames = dropped;
-            }
-
-            return info;
-        }
-    }]);
-
-    return NativePlayer;
-}();
-
-exports.default = NativePlayer;
-
-},{"../config.js":5,"../utils/exception.js":40,"./player-events.js":35,"events":2}],34:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-exports.ErrorDetails = exports.ErrorTypes = undefined;
-
-var _loader = _dereq_('../io/loader.js');
-
-var _demuxErrors = _dereq_('../demux/demux-errors.js');
-
-var _demuxErrors2 = _interopRequireDefault(_demuxErrors);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var ErrorTypes = exports.ErrorTypes = {
-    NETWORK_ERROR: 'NetworkError',
-    MEDIA_ERROR: 'MediaError',
-    OTHER_ERROR: 'OtherError'
-};
-
-var ErrorDetails = exports.ErrorDetails = {
-    NETWORK_EXCEPTION: _loader.LoaderErrors.EXCEPTION,
-    NETWORK_STATUS_CODE_INVALID: _loader.LoaderErrors.HTTP_STATUS_CODE_INVALID,
-    NETWORK_TIMEOUT: _loader.LoaderErrors.CONNECTING_TIMEOUT,
-    NETWORK_UNRECOVERABLE_EARLY_EOF: _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF,
-
-    MEDIA_MSE_ERROR: 'MediaMSEError',
-
-    MEDIA_FORMAT_ERROR: _demuxErrors2.default.FORMAT_ERROR,
-    MEDIA_FORMAT_UNSUPPORTED: _demuxErrors2.default.FORMAT_UNSUPPORTED,
-    MEDIA_CODEC_UNSUPPORTED: _demuxErrors2.default.CODEC_UNSUPPORTED
-};
-
-},{"../demux/demux-errors.js":16,"../io/loader.js":24}],35:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var PlayerEvents = {
-  ERROR: 'error',
-  LOADING_COMPLETE: 'loading_complete',
-  RECOVERED_EARLY_EOF: 'recovered_early_eof',
-  MEDIA_INFO: 'media_info',
-  METADATA_ARRIVED: 'metadata_arrived',
-  SCRIPTDATA_ARRIVED: 'scriptdata_arrived',
-  STATISTICS_INFO: 'statistics_info'
-};
-
-exports.default = PlayerEvents;
-
-},{}],36:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * This file is modified from dailymotion's hls.js library (hls.js/src/helper/aac.js)
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var AAC = function () {
-    function AAC() {
-        _classCallCheck(this, AAC);
-    }
-
-    _createClass(AAC, null, [{
-        key: 'getSilentFrame',
-        value: function getSilentFrame(codec, channelCount) {
-            if (codec === 'mp4a.40.2') {
-                // handle LC-AAC
-                if (channelCount === 1) {
-                    return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x23, 0x80]);
-                } else if (channelCount === 2) {
-                    return new Uint8Array([0x21, 0x00, 0x49, 0x90, 0x02, 0x19, 0x00, 0x23, 0x80]);
-                } else if (channelCount === 3) {
-                    return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x8e]);
-                } else if (channelCount === 4) {
-                    return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x80, 0x2c, 0x80, 0x08, 0x02, 0x38]);
-                } else if (channelCount === 5) {
-                    return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x82, 0x30, 0x04, 0x99, 0x00, 0x21, 0x90, 0x02, 0x38]);
-                } else if (channelCount === 6) {
-                    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]);
-                }
-            } else {
-                // handle HE-AAC (mp4a.40.5 / mp4a.40.29)
-                if (channelCount === 1) {
-                    // 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
-                    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]);
-                } else if (channelCount === 2) {
-                    // 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
-                    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]);
-                } else if (channelCount === 3) {
-                    // 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
-                    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]);
-                }
-            }
-            return null;
-        }
-    }]);
-
-    return AAC;
-}();
-
-exports.default = AAC;
-
-},{}],37:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * This file is derived from dailymotion's hls.js library (hls.js/src/remux/mp4-generator.js)
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//  MP4 boxes generator for ISO BMFF (ISO Base Media File Format, defined in ISO/IEC 14496-12)
-var MP4 = function () {
-    function MP4() {
-        _classCallCheck(this, MP4);
-    }
-
-    _createClass(MP4, null, [{
-        key: 'init',
-        value: function init() {
-            MP4.types = {
-                avc1: [], avcC: [], btrt: [], dinf: [],
-                dref: [], esds: [], ftyp: [], hdlr: [],
-                mdat: [], mdhd: [], mdia: [], mfhd: [],
-                minf: [], moof: [], moov: [], mp4a: [],
-                mvex: [], mvhd: [], sdtp: [], stbl: [],
-                stco: [], stsc: [], stsd: [], stsz: [],
-                stts: [], tfdt: [], tfhd: [], traf: [],
-                trak: [], trun: [], trex: [], tkhd: [],
-                vmhd: [], smhd: [], '.mp3': []
-            };
-
-            for (var name in MP4.types) {
-                if (MP4.types.hasOwnProperty(name)) {
-                    MP4.types[name] = [name.charCodeAt(0), name.charCodeAt(1), name.charCodeAt(2), name.charCodeAt(3)];
-                }
-            }
-
-            var constants = MP4.constants = {};
-
-            constants.FTYP = new Uint8Array([0x69, 0x73, 0x6F, 0x6D, // major_brand: isom
-            0x0, 0x0, 0x0, 0x1, // minor_version: 0x01
-            0x69, 0x73, 0x6F, 0x6D, // isom
-            0x61, 0x76, 0x63, 0x31 // avc1
-            ]);
-
-            constants.STSD_PREFIX = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            0x00, 0x00, 0x00, 0x01 // entry_count
-            ]);
-
-            constants.STTS = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            0x00, 0x00, 0x00, 0x00 // entry_count
-            ]);
-
-            constants.STSC = constants.STCO = constants.STTS;
-
-            constants.STSZ = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            0x00, 0x00, 0x00, 0x00, // sample_size
-            0x00, 0x00, 0x00, 0x00 // sample_count
-            ]);
-
-            constants.HDLR_VIDEO = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            0x00, 0x00, 0x00, 0x00, // pre_defined
-            0x76, 0x69, 0x64, 0x65, // handler_type: 'vide'
-            0x00, 0x00, 0x00, 0x00, // reserved: 3 * 4 bytes
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x69, 0x64, 0x65, 0x6F, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00 // name: VideoHandler
-            ]);
-
-            constants.HDLR_AUDIO = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            0x00, 0x00, 0x00, 0x00, // pre_defined
-            0x73, 0x6F, 0x75, 0x6E, // handler_type: 'soun'
-            0x00, 0x00, 0x00, 0x00, // reserved: 3 * 4 bytes
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x6F, 0x75, 0x6E, 0x64, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00 // name: SoundHandler
-            ]);
-
-            constants.DREF = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            0x00, 0x00, 0x00, 0x01, // entry_count
-            0x00, 0x00, 0x00, 0x0C, // entry_size
-            0x75, 0x72, 0x6C, 0x20, // type 'url '
-            0x00, 0x00, 0x00, 0x01 // version(0) + flags
-            ]);
-
-            // Sound media header
-            constants.SMHD = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            0x00, 0x00, 0x00, 0x00 // balance(2) + reserved(2)
-            ]);
-
-            // video media header
-            constants.VMHD = new Uint8Array([0x00, 0x00, 0x00, 0x01, // version(0) + flags
-            0x00, 0x00, // graphicsmode: 2 bytes
-            0x00, 0x00, 0x00, 0x00, // opcolor: 3 * 2 bytes
-            0x00, 0x00]);
-        }
-
-        // Generate a box
-
-    }, {
-        key: 'box',
-        value: function box(type) {
-            var size = 8;
-            var result = null;
-            var datas = Array.prototype.slice.call(arguments, 1);
-            var arrayCount = datas.length;
-
-            for (var i = 0; i < arrayCount; i++) {
-                size += datas[i].byteLength;
-            }
-
-            result = new Uint8Array(size);
-            result[0] = size >>> 24 & 0xFF; // size
-            result[1] = size >>> 16 & 0xFF;
-            result[2] = size >>> 8 & 0xFF;
-            result[3] = size & 0xFF;
-
-            result.set(type, 4); // type
-
-            var offset = 8;
-            for (var _i = 0; _i < arrayCount; _i++) {
-                // data body
-                result.set(datas[_i], offset);
-                offset += datas[_i].byteLength;
-            }
-
-            return result;
-        }
-
-        // emit ftyp & moov
-
-    }, {
-        key: 'generateInitSegment',
-        value: function generateInitSegment(meta) {
-            var ftyp = MP4.box(MP4.types.ftyp, MP4.constants.FTYP);
-            var moov = MP4.moov(meta);
-
-            var result = new Uint8Array(ftyp.byteLength + moov.byteLength);
-            result.set(ftyp, 0);
-            result.set(moov, ftyp.byteLength);
-            return result;
-        }
-
-        // Movie metadata box
-
-    }, {
-        key: 'moov',
-        value: function moov(meta) {
-            var mvhd = MP4.mvhd(meta.timescale, meta.duration);
-            var trak = MP4.trak(meta);
-            var mvex = MP4.mvex(meta);
-            return MP4.box(MP4.types.moov, mvhd, trak, mvex);
-        }
-
-        // Movie header box
-
-    }, {
-        key: 'mvhd',
-        value: function mvhd(timescale, duration) {
-            return MP4.box(MP4.types.mvhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            0x00, 0x00, 0x00, 0x00, // creation_time
-            0x00, 0x00, 0x00, 0x00, // modification_time
-            timescale >>> 24 & 0xFF, // timescale: 4 bytes
-            timescale >>> 16 & 0xFF, timescale >>> 8 & 0xFF, timescale & 0xFF, duration >>> 24 & 0xFF, // duration: 4 bytes
-            duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, 0x00, 0x01, 0x00, 0x00, // Preferred rate: 1.0
-            0x01, 0x00, 0x00, 0x00, // PreferredVolume(1.0, 2bytes) + reserved(2bytes)
-            0x00, 0x00, 0x00, 0x00, // reserved: 4 + 4 bytes
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ----begin composition matrix----
-            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----
-            0x00, 0x00, 0x00, 0x00, // ----begin pre_defined 6 * 4 bytes----
-            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----
-            0xFF, 0xFF, 0xFF, 0xFF // next_track_ID
-            ]));
-        }
-
-        // Track box
-
-    }, {
-        key: 'trak',
-        value: function trak(meta) {
-            return MP4.box(MP4.types.trak, MP4.tkhd(meta), MP4.mdia(meta));
-        }
-
-        // Track header box
-
-    }, {
-        key: 'tkhd',
-        value: function tkhd(meta) {
-            var trackId = meta.id,
-                duration = meta.duration;
-            var width = meta.presentWidth,
-                height = meta.presentHeight;
-
-            return MP4.box(MP4.types.tkhd, new Uint8Array([0x00, 0x00, 0x00, 0x07, // version(0) + flags
-            0x00, 0x00, 0x00, 0x00, // creation_time
-            0x00, 0x00, 0x00, 0x00, // modification_time
-            trackId >>> 24 & 0xFF, // track_ID: 4 bytes
-            trackId >>> 16 & 0xFF, trackId >>> 8 & 0xFF, trackId & 0xFF, 0x00, 0x00, 0x00, 0x00, // reserved: 4 bytes
-            duration >>> 24 & 0xFF, // duration: 4 bytes
-            duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, 0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // layer(2bytes) + alternate_group(2bytes)
-            0x00, 0x00, 0x00, 0x00, // volume(2bytes) + reserved(2bytes)
-            0x00, 0x01, 0x00, 0x00, // ----begin composition matrix----
-            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----
-            width >>> 8 & 0xFF, // width and height
-            width & 0xFF, 0x00, 0x00, height >>> 8 & 0xFF, height & 0xFF, 0x00, 0x00]));
-        }
-
-        // Media Box
-
-    }, {
-        key: 'mdia',
-        value: function mdia(meta) {
-            return MP4.box(MP4.types.mdia, MP4.mdhd(meta), MP4.hdlr(meta), MP4.minf(meta));
-        }
-
-        // Media header box
-
-    }, {
-        key: 'mdhd',
-        value: function mdhd(meta) {
-            var timescale = meta.timescale;
-            var duration = meta.duration;
-            return MP4.box(MP4.types.mdhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            0x00, 0x00, 0x00, 0x00, // creation_time
-            0x00, 0x00, 0x00, 0x00, // modification_time
-            timescale >>> 24 & 0xFF, // timescale: 4 bytes
-            timescale >>> 16 & 0xFF, timescale >>> 8 & 0xFF, timescale & 0xFF, duration >>> 24 & 0xFF, // duration: 4 bytes
-            duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, 0x55, 0xC4, // language: und (undetermined)
-            0x00, 0x00 // pre_defined = 0
-            ]));
-        }
-
-        // Media handler reference box
-
-    }, {
-        key: 'hdlr',
-        value: function hdlr(meta) {
-            var data = null;
-            if (meta.type === 'audio') {
-                data = MP4.constants.HDLR_AUDIO;
-            } else {
-                data = MP4.constants.HDLR_VIDEO;
-            }
-            return MP4.box(MP4.types.hdlr, data);
-        }
-
-        // Media infomation box
-
-    }, {
-        key: 'minf',
-        value: function minf(meta) {
-            var xmhd = null;
-            if (meta.type === 'audio') {
-                xmhd = MP4.box(MP4.types.smhd, MP4.constants.SMHD);
-            } else {
-                xmhd = MP4.box(MP4.types.vmhd, MP4.constants.VMHD);
-            }
-            return MP4.box(MP4.types.minf, xmhd, MP4.dinf(), MP4.stbl(meta));
-        }
-
-        // Data infomation box
-
-    }, {
-        key: 'dinf',
-        value: function dinf() {
-            var result = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, MP4.constants.DREF));
-            return result;
-        }
-
-        // Sample table box
-
-    }, {
-        key: 'stbl',
-        value: function stbl(meta) {
-            var result = MP4.box(MP4.types.stbl, // type: stbl
-            MP4.stsd(meta), // Sample Description Table
-            MP4.box(MP4.types.stts, MP4.constants.STTS), // Time-To-Sample
-            MP4.box(MP4.types.stsc, MP4.constants.STSC), // Sample-To-Chunk
-            MP4.box(MP4.types.stsz, MP4.constants.STSZ), // Sample size
-            MP4.box(MP4.types.stco, MP4.constants.STCO // Chunk offset
-            ));
-            return result;
-        }
-
-        // Sample description box
-
-    }, {
-        key: 'stsd',
-        value: function stsd(meta) {
-            if (meta.type === 'audio') {
-                if (meta.codec === 'mp3') {
-                    return MP4.box(MP4.types.stsd, MP4.constants.STSD_PREFIX, MP4.mp3(meta));
-                }
-                // else: aac -> mp4a
-                return MP4.box(MP4.types.stsd, MP4.constants.STSD_PREFIX, MP4.mp4a(meta));
-            } else {
-                return MP4.box(MP4.types.stsd, MP4.constants.STSD_PREFIX, MP4.avc1(meta));
-            }
-        }
-    }, {
-        key: 'mp3',
-        value: function mp3(meta) {
-            var channelCount = meta.channelCount;
-            var sampleRate = meta.audioSampleRate;
-
-            var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // reserved(4)
-            0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
-            0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
-            0x00, 0x00, 0x00, 0x00, 0x00, channelCount, // channelCount(2)
-            0x00, 0x10, // sampleSize(2)
-            0x00, 0x00, 0x00, 0x00, // reserved(4)
-            sampleRate >>> 8 & 0xFF, // Audio sample rate
-            sampleRate & 0xFF, 0x00, 0x00]);
-
-            return MP4.box(MP4.types['.mp3'], data);
-        }
-    }, {
-        key: 'mp4a',
-        value: function mp4a(meta) {
-            var channelCount = meta.channelCount;
-            var sampleRate = meta.audioSampleRate;
-
-            var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // reserved(4)
-            0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
-            0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
-            0x00, 0x00, 0x00, 0x00, 0x00, channelCount, // channelCount(2)
-            0x00, 0x10, // sampleSize(2)
-            0x00, 0x00, 0x00, 0x00, // reserved(4)
-            sampleRate >>> 8 & 0xFF, // Audio sample rate
-            sampleRate & 0xFF, 0x00, 0x00]);
-
-            return MP4.box(MP4.types.mp4a, data, MP4.esds(meta));
-        }
-    }, {
-        key: 'esds',
-        value: function esds(meta) {
-            var config = meta.config || [];
-            var configSize = config.length;
-            var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version 0 + flags
-
-            0x03, // descriptor_type
-            0x17 + configSize, // length3
-            0x00, 0x01, // es_id
-            0x00, // stream_priority
-
-            0x04, // descriptor_type
-            0x0F + configSize, // length
-            0x40, // codec: mpeg4_audio
-            0x15, // stream_type: Audio
-            0x00, 0x00, 0x00, // buffer_size
-            0x00, 0x00, 0x00, 0x00, // maxBitrate
-            0x00, 0x00, 0x00, 0x00, // avgBitrate
-
-            0x05 // descriptor_type
-            ].concat([configSize]).concat(config).concat([0x06, 0x01, 0x02 // GASpecificConfig
-            ]));
-            return MP4.box(MP4.types.esds, data);
-        }
-    }, {
-        key: 'avc1',
-        value: function avc1(meta) {
-            var avcc = meta.avcc;
-            var width = meta.codecWidth,
-                height = meta.codecHeight;
-
-            var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // reserved(4)
-            0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
-            0x00, 0x00, 0x00, 0x00, // pre_defined(2) + reserved(2)
-            0x00, 0x00, 0x00, 0x00, // pre_defined: 3 * 4 bytes
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, width >>> 8 & 0xFF, // width: 2 bytes
-            width & 0xFF, height >>> 8 & 0xFF, // height: 2 bytes
-            height & 0xFF, 0x00, 0x48, 0x00, 0x00, // horizresolution: 4 bytes
-            0x00, 0x48, 0x00, 0x00, // vertresolution: 4 bytes
-            0x00, 0x00, 0x00, 0x00, // reserved: 4 bytes
-            0x00, 0x01, // frame_count
-            0x0A, // strlen
-            0x78, 0x71, 0x71, 0x2F, // compressorname: 32 bytes
-            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
-            0xFF, 0xFF // pre_defined = -1
-            ]);
-            return MP4.box(MP4.types.avc1, data, MP4.box(MP4.types.avcC, avcc));
-        }
-
-        // Movie Extends box
-
-    }, {
-        key: 'mvex',
-        value: function mvex(meta) {
-            return MP4.box(MP4.types.mvex, MP4.trex(meta));
-        }
-
-        // Track Extends box
-
-    }, {
-        key: 'trex',
-        value: function trex(meta) {
-            var trackId = meta.id;
-            var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
-            trackId >>> 24 & 0xFF, // track_ID
-            trackId >>> 16 & 0xFF, trackId >>> 8 & 0xFF, trackId & 0xFF, 0x00, 0x00, 0x00, 0x01, // default_sample_description_index
-            0x00, 0x00, 0x00, 0x00, // default_sample_duration
-            0x00, 0x00, 0x00, 0x00, // default_sample_size
-            0x00, 0x01, 0x00, 0x01 // default_sample_flags
-            ]);
-            return MP4.box(MP4.types.trex, data);
-        }
-
-        // Movie fragment box
-
-    }, {
-        key: 'moof',
-        value: function moof(track, baseMediaDecodeTime) {
-            return MP4.box(MP4.types.moof, MP4.mfhd(track.sequenceNumber), MP4.traf(track, baseMediaDecodeTime));
-        }
-    }, {
-        key: 'mfhd',
-        value: function mfhd(sequenceNumber) {
-            var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, sequenceNumber >>> 24 & 0xFF, // sequence_number: int32
-            sequenceNumber >>> 16 & 0xFF, sequenceNumber >>> 8 & 0xFF, sequenceNumber & 0xFF]);
-            return MP4.box(MP4.types.mfhd, data);
-        }
-
-        // Track fragment box
-
-    }, {
-        key: 'traf',
-        value: function traf(track, baseMediaDecodeTime) {
-            var trackId = track.id;
-
-            // Track fragment header box
-            var tfhd = MP4.box(MP4.types.tfhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) & flags
-            trackId >>> 24 & 0xFF, // track_ID
-            trackId >>> 16 & 0xFF, trackId >>> 8 & 0xFF, trackId & 0xFF]));
-            // Track Fragment Decode Time
-            var tfdt = MP4.box(MP4.types.tfdt, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) & flags
-            baseMediaDecodeTime >>> 24 & 0xFF, // baseMediaDecodeTime: int32
-            baseMediaDecodeTime >>> 16 & 0xFF, baseMediaDecodeTime >>> 8 & 0xFF, baseMediaDecodeTime & 0xFF]));
-            var sdtp = MP4.sdtp(track);
-            var trun = MP4.trun(track, sdtp.byteLength + 16 + 16 + 8 + 16 + 8 + 8);
-
-            return MP4.box(MP4.types.traf, tfhd, tfdt, trun, sdtp);
-        }
-
-        // Sample Dependency Type box
-
-    }, {
-        key: 'sdtp',
-        value: function sdtp(track) {
-            var samples = track.samples || [];
-            var sampleCount = samples.length;
-            var data = new Uint8Array(4 + sampleCount);
-            // 0~4 bytes: version(0) & flags
-            for (var i = 0; i < sampleCount; i++) {
-                var flags = samples[i].flags;
-                data[i + 4] = flags.isLeading << 6 | // is_leading: 2 (bit)
-                flags.dependsOn << 4 // sample_depends_on
-                | flags.isDependedOn << 2 // sample_is_depended_on
-                | flags.hasRedundancy; // sample_has_redundancy
-            }
-            return MP4.box(MP4.types.sdtp, data);
-        }
-
-        // Track fragment run box
-
-    }, {
-        key: 'trun',
-        value: function trun(track, offset) {
-            var samples = track.samples || [];
-            var sampleCount = samples.length;
-            var dataSize = 12 + 16 * sampleCount;
-            var data = new Uint8Array(dataSize);
-            offset += 8 + dataSize;
-
-            data.set([0x00, 0x00, 0x0F, 0x01, // version(0) & flags
-            sampleCount >>> 24 & 0xFF, // sample_count
-            sampleCount >>> 16 & 0xFF, sampleCount >>> 8 & 0xFF, sampleCount & 0xFF, offset >>> 24 & 0xFF, // data_offset
-            offset >>> 16 & 0xFF, offset >>> 8 & 0xFF, offset & 0xFF], 0);
-
-            for (var i = 0; i < sampleCount; i++) {
-                var duration = samples[i].duration;
-                var size = samples[i].size;
-                var flags = samples[i].flags;
-                var cts = samples[i].cts;
-                data.set([duration >>> 24 & 0xFF, // sample_duration
-                duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, size >>> 24 & 0xFF, // sample_size
-                size >>> 16 & 0xFF, size >>> 8 & 0xFF, size & 0xFF, flags.isLeading << 2 | flags.dependsOn, // sample_flags
-                flags.isDependedOn << 6 | flags.hasRedundancy << 4 | flags.isNonSync, 0x00, 0x00, // sample_degradation_priority
-                cts >>> 24 & 0xFF, // sample_composition_time_offset
-                cts >>> 16 & 0xFF, cts >>> 8 & 0xFF, cts & 0xFF], 12 + 16 * i);
-            }
-            return MP4.box(MP4.types.trun, data);
-        }
-    }, {
-        key: 'mdat',
-        value: function mdat(data) {
-            return MP4.box(MP4.types.mdat, data);
-        }
-    }]);
-
-    return MP4;
-}();
-
-MP4.init();
-
-exports.default = MP4;
-
-},{}],38:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
-
-var _logger = _dereq_('../utils/logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-var _mp4Generator = _dereq_('./mp4-generator.js');
-
-var _mp4Generator2 = _interopRequireDefault(_mp4Generator);
-
-var _aacSilent = _dereq_('./aac-silent.js');
-
-var _aacSilent2 = _interopRequireDefault(_aacSilent);
-
-var _browser = _dereq_('../utils/browser.js');
-
-var _browser2 = _interopRequireDefault(_browser);
-
-var _mediaSegmentInfo = _dereq_('../core/media-segment-info.js');
-
-var _exception = _dereq_('../utils/exception.js');
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-// Fragmented mp4 remuxer
-var MP4Remuxer = function () {
-    function MP4Remuxer(config) {
-        _classCallCheck(this, MP4Remuxer);
-
-        this.TAG = 'MP4Remuxer';
-
-        this._config = config;
-        this._isLive = config.isLive === true ? true : false;
-
-        this._dtsBase = -1;
-        this._dtsBaseInited = false;
-        this._audioDtsBase = Infinity;
-        this._videoDtsBase = Infinity;
-        this._audioNextDts = undefined;
-        this._videoNextDts = undefined;
-        this._audioStashedLastSample = null;
-        this._videoStashedLastSample = null;
-
-        this._audioMeta = null;
-        this._videoMeta = null;
-
-        this._audioSegmentInfoList = new _mediaSegmentInfo.MediaSegmentInfoList('audio');
-        this._videoSegmentInfoList = new _mediaSegmentInfo.MediaSegmentInfoList('video');
-
-        this._onInitSegment = null;
-        this._onMediaSegment = null;
-
-        // Workaround for chrome < 50: Always force first sample as a Random Access Point in media segment
-        // see https://bugs.chromium.org/p/chromium/issues/detail?id=229412
-        this._forceFirstIDR = _browser2.default.chrome && (_browser2.default.version.major < 50 || _browser2.default.version.major === 50 && _browser2.default.version.build < 2661) ? true : false;
-
-        // Workaround for IE11/Edge: Fill silent aac frame after keyframe-seeking
-        // Make audio beginDts equals with video beginDts, in order to fix seek freeze
-        this._fillSilentAfterSeek = _browser2.default.msedge || _browser2.default.msie;
-
-        // While only FireFox supports 'audio/mp4, codecs="mp3"', use 'audio/mpeg' for chrome, safari, ...
-        this._mp3UseMpegAudio = !_browser2.default.firefox;
-
-        this._fillAudioTimestampGap = this._config.fixAudioTimestampGap;
-    }
-
-    _createClass(MP4Remuxer, [{
-        key: 'destroy',
-        value: function destroy() {
-            this._dtsBase = -1;
-            this._dtsBaseInited = false;
-            this._audioMeta = null;
-            this._videoMeta = null;
-            this._audioSegmentInfoList.clear();
-            this._audioSegmentInfoList = null;
-            this._videoSegmentInfoList.clear();
-            this._videoSegmentInfoList = null;
-            this._onInitSegment = null;
-            this._onMediaSegment = null;
-        }
-    }, {
-        key: 'bindDataSource',
-        value: function bindDataSource(producer) {
-            producer.onDataAvailable = this.remux.bind(this);
-            producer.onTrackMetadata = this._onTrackMetadataReceived.bind(this);
-            return this;
-        }
-
-        /* prototype: function onInitSegment(type: string, initSegment: ArrayBuffer): void
-           InitSegment: {
-               type: string,
-               data: ArrayBuffer,
-               codec: string,
-               container: string
-           }
-        */
-
-    }, {
-        key: 'insertDiscontinuity',
-        value: function insertDiscontinuity() {
-            this._audioNextDts = this._videoNextDts = undefined;
-        }
-    }, {
-        key: 'seek',
-        value: function seek(originalDts) {
-            this._audioStashedLastSample = null;
-            this._videoStashedLastSample = null;
-            this._videoSegmentInfoList.clear();
-            this._audioSegmentInfoList.clear();
-        }
-    }, {
-        key: 'remux',
-        value: function remux(audioTrack, videoTrack) {
-            if (!this._onMediaSegment) {
-                throw new _exception.IllegalStateException('MP4Remuxer: onMediaSegment callback must be specificed!');
-            }
-            if (!this._dtsBaseInited) {
-                this._calculateDtsBase(audioTrack, videoTrack);
-            }
-            this._remuxVideo(videoTrack);
-            this._remuxAudio(audioTrack);
-        }
-    }, {
-        key: '_onTrackMetadataReceived',
-        value: function _onTrackMetadataReceived(type, metadata) {
-            var metabox = null;
-
-            var container = 'mp4';
-            var codec = metadata.codec;
-
-            if (type === 'audio') {
-                this._audioMeta = metadata;
-                if (metadata.codec === 'mp3' && this._mp3UseMpegAudio) {
-                    // 'audio/mpeg' for MP3 audio track
-                    container = 'mpeg';
-                    codec = '';
-                    metabox = new Uint8Array();
-                } else {
-                    // 'audio/mp4, codecs="codec"'
-                    metabox = _mp4Generator2.default.generateInitSegment(metadata);
-                }
-            } else if (type === 'video') {
-                this._videoMeta = metadata;
-                metabox = _mp4Generator2.default.generateInitSegment(metadata);
-            } else {
-                return;
-            }
-
-            // dispatch metabox (Initialization Segment)
-            if (!this._onInitSegment) {
-                throw new _exception.IllegalStateException('MP4Remuxer: onInitSegment callback must be specified!');
-            }
-            this._onInitSegment(type, {
-                type: type,
-                data: metabox.buffer,
-                codec: codec,
-                container: type + '/' + container,
-                mediaDuration: metadata.duration // in timescale 1000 (milliseconds)
-            });
-        }
-    }, {
-        key: '_calculateDtsBase',
-        value: function _calculateDtsBase(audioTrack, videoTrack) {
-            if (this._dtsBaseInited) {
-                return;
-            }
-
-            if (audioTrack.samples && audioTrack.samples.length) {
-                this._audioDtsBase = audioTrack.samples[0].dts;
-            }
-            if (videoTrack.samples && videoTrack.samples.length) {
-                this._videoDtsBase = videoTrack.samples[0].dts;
-            }
-
-            this._dtsBase = Math.min(this._audioDtsBase, this._videoDtsBase);
-            this._dtsBaseInited = true;
-        }
-    }, {
-        key: 'flushStashedSamples',
-        value: function flushStashedSamples() {
-            var videoSample = this._videoStashedLastSample;
-            var audioSample = this._audioStashedLastSample;
-
-            var videoTrack = {
-                type: 'video',
-                id: 1,
-                sequenceNumber: 0,
-                samples: [],
-                length: 0
-            };
-
-            if (videoSample != null) {
-                videoTrack.samples.push(videoSample);
-                videoTrack.length = videoSample.length;
-            }
-
-            var audioTrack = {
-                type: 'audio',
-                id: 2,
-                sequenceNumber: 0,
-                samples: [],
-                length: 0
-            };
-
-            if (audioSample != null) {
-                audioTrack.samples.push(audioSample);
-                audioTrack.length = audioSample.length;
-            }
-
-            this._videoStashedLastSample = null;
-            this._audioStashedLastSample = null;
-
-            this._remuxVideo(videoTrack, true);
-            this._remuxAudio(audioTrack, true);
-        }
-    }, {
-        key: '_remuxAudio',
-        value: function _remuxAudio(audioTrack, force) {
-            if (this._audioMeta == null) {
-                return;
-            }
-
-            var track = audioTrack;
-            var samples = track.samples;
-            var dtsCorrection = undefined;
-            var firstDts = -1,
-                lastDts = -1,
-                lastPts = -1;
-            var refSampleDuration = this._audioMeta.refSampleDuration;
-
-            var mpegRawTrack = this._audioMeta.codec === 'mp3' && this._mp3UseMpegAudio;
-            var firstSegmentAfterSeek = this._dtsBaseInited && this._audioNextDts === undefined;
-
-            var insertPrefixSilentFrame = false;
-
-            if (!samples || samples.length === 0) {
-                return;
-            }
-            if (samples.length === 1 && !force) {
-                // If [sample count in current batch] === 1 && (force != true)
-                // Ignore and keep in demuxer's queue
-                return;
-            } // else if (force === true) do remux
-
-            var offset = 0;
-            var mdatbox = null;
-            var mdatBytes = 0;
-
-            // calculate initial mdat size
-            if (mpegRawTrack) {
-                // for raw mpeg buffer
-                offset = 0;
-                mdatBytes = track.length;
-            } else {
-                // for fmp4 mdat box
-                offset = 8; // size + type
-                mdatBytes = 8 + track.length;
-            }
-
-            var lastSample = null;
-
-            // Pop the lastSample and waiting for stash
-            if (samples.length > 1) {
-                lastSample = samples.pop();
-                mdatBytes -= lastSample.length;
-            }
-
-            // Insert [stashed lastSample in the previous batch] to the front
-            if (this._audioStashedLastSample != null) {
-                var sample = this._audioStashedLastSample;
-                this._audioStashedLastSample = null;
-                samples.unshift(sample);
-                mdatBytes += sample.length;
-            }
-
-            // Stash the lastSample of current batch, waiting for next batch
-            if (lastSample != null) {
-                this._audioStashedLastSample = lastSample;
-            }
-
-            var firstSampleOriginalDts = samples[0].dts - this._dtsBase;
-
-            // calculate dtsCorrection
-            if (this._audioNextDts) {
-                dtsCorrection = firstSampleOriginalDts - this._audioNextDts;
-            } else {
-                // this._audioNextDts == undefined
-                if (this._audioSegmentInfoList.isEmpty()) {
-                    dtsCorrection = 0;
-                    if (this._fillSilentAfterSeek && !this._videoSegmentInfoList.isEmpty()) {
-                        if (this._audioMeta.originalCodec !== 'mp3') {
-                            insertPrefixSilentFrame = true;
-                        }
-                    }
-                } else {
-                    var _lastSample = this._audioSegmentInfoList.getLastSampleBefore(firstSampleOriginalDts);
-                    if (_lastSample != null) {
-                        var distance = firstSampleOriginalDts - (_lastSample.originalDts + _lastSample.duration);
-                        if (distance <= 3) {
-                            distance = 0;
-                        }
-                        var expectedDts = _lastSample.dts + _lastSample.duration + distance;
-                        dtsCorrection = firstSampleOriginalDts - expectedDts;
-                    } else {
-                        // lastSample == null, cannot found
-                        dtsCorrection = 0;
-                    }
-                }
-            }
-
-            if (insertPrefixSilentFrame) {
-                // align audio segment beginDts to match with current video segment's beginDts
-                var firstSampleDts = firstSampleOriginalDts - dtsCorrection;
-                var videoSegment = this._videoSegmentInfoList.getLastSegmentBefore(firstSampleOriginalDts);
-                if (videoSegment != null && videoSegment.beginDts < firstSampleDts) {
-                    var silentUnit = _aacSilent2.default.getSilentFrame(this._audioMeta.originalCodec, this._audioMeta.channelCount);
-                    if (silentUnit) {
-                        var dts = videoSegment.beginDts;
-                        var silentFrameDuration = firstSampleDts - videoSegment.beginDts;
-                        _logger2.default.v(this.TAG, 'InsertPrefixSilentAudio: dts: ' + dts + ', duration: ' + silentFrameDuration);
-                        samples.unshift({ unit: silentUnit, dts: dts, pts: dts });
-                        mdatBytes += silentUnit.byteLength;
-                    } // silentUnit == null: Cannot generate, skip
-                } else {
-                    insertPrefixSilentFrame = false;
-                }
-            }
-
-            var mp4Samples = [];
-
-            // Correct dts for each sample, and calculate sample duration. Then output to mp4Samples
-            for (var i = 0; i < samples.length; i++) {
-                var _sample = samples[i];
-                var unit = _sample.unit;
-                var originalDts = _sample.dts - this._dtsBase;
-                var _dts = originalDts - dtsCorrection;
-
-                if (firstDts === -1) {
-                    firstDts = _dts;
-                }
-
-                var sampleDuration = 0;
-
-                if (i !== samples.length - 1) {
-                    var nextDts = samples[i + 1].dts - this._dtsBase - dtsCorrection;
-                    sampleDuration = nextDts - _dts;
-                } else {
-                    // the last sample
-                    if (lastSample != null) {
-                        // use stashed sample's dts to calculate sample duration
-                        var _nextDts = lastSample.dts - this._dtsBase - dtsCorrection;
-                        sampleDuration = _nextDts - _dts;
-                    } else if (mp4Samples.length >= 1) {
-                        // use second last sample duration
-                        sampleDuration = mp4Samples[mp4Samples.length - 1].duration;
-                    } else {
-                        // the only one sample, use reference sample duration
-                        sampleDuration = Math.floor(refSampleDuration);
-                    }
-                }
-
-                var needFillSilentFrames = false;
-                var silentFrames = null;
-
-                // Silent frame generation, if large timestamp gap detected && config.fixAudioTimestampGap
-                if (sampleDuration > refSampleDuration * 1.5 && this._audioMeta.codec !== 'mp3' && this._fillAudioTimestampGap && !_browser2.default.safari) {
-                    // We need to insert silent frames to fill timestamp gap
-                    needFillSilentFrames = true;
-                    var delta = Math.abs(sampleDuration - refSampleDuration);
-                    var frameCount = Math.ceil(delta / refSampleDuration);
-                    var currentDts = _dts + refSampleDuration; // Notice: in float
-
-                    _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'));
-
-                    var _silentUnit = _aacSilent2.default.getSilentFrame(this._audioMeta.originalCodec, this._audioMeta.channelCount);
-                    if (_silentUnit == null) {
-                        _logger2.default.w(this.TAG, 'Unable to generate silent frame for ' + (this._audioMeta.originalCodec + ' with ' + this._audioMeta.channelCount + ' channels, repeat last frame'));
-                        // Repeat last frame
-                        _silentUnit = unit;
-                    }
-                    silentFrames = [];
-
-                    for (var j = 0; j < frameCount; j++) {
-                        var intDts = Math.round(currentDts); // round to integer
-                        if (silentFrames.length > 0) {
-                            // Set previous frame sample duration
-                            var previousFrame = silentFrames[silentFrames.length - 1];
-                            previousFrame.duration = intDts - previousFrame.dts;
-                        }
-                        var frame = {
-                            dts: intDts,
-                            pts: intDts,
-                            cts: 0,
-                            unit: _silentUnit,
-                            size: _silentUnit.byteLength,
-                            duration: 0, // wait for next sample
-                            originalDts: originalDts,
-                            flags: {
-                                isLeading: 0,
-                                dependsOn: 1,
-                                isDependedOn: 0,
-                                hasRedundancy: 0
+                            // lazyLoad check
+                            if (_this3._config.lazyLoad && !_this3._config.isLive) {
+                                var currentTime = _this3._mediaElement.currentTime;
+                                if (ms.info.endDts >= (currentTime + _this3._config.lazyLoadMaxDuration) * 1000) {
+                                    if (_this3._progressChecker == null) {
+                                        _logger2.default.v(_this3.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
+                                        _this3._suspendTransmuxer();
+                                    }
+                                }
                             }
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.LOADING_COMPLETE, function () {
+                            _this3._msectl.endOfStream();
+                            _this3._emitter.emit(_playerEvents2.default.LOADING_COMPLETE);
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.RECOVERED_EARLY_EOF, function () {
+                            _this3._emitter.emit(_playerEvents2.default.RECOVERED_EARLY_EOF);
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.IO_ERROR, function (detail, info) {
+                            _this3._emitter.emit(_playerEvents2.default.ERROR, _playerErrors.ErrorTypes.NETWORK_ERROR, detail, info);
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.DEMUX_ERROR, function (detail, info) {
+                            _this3._emitter.emit(_playerEvents2.default.ERROR, _playerErrors.ErrorTypes.MEDIA_ERROR, detail, { code: -1, msg: info });
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.MEDIA_INFO, function (mediaInfo) {
+                            _this3._mediaInfo = mediaInfo;
+                            _this3._emitter.emit(_playerEvents2.default.MEDIA_INFO, Object.assign({}, mediaInfo));
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.METADATA_ARRIVED, function (metadata) {
+                            _this3._emitter.emit(_playerEvents2.default.METADATA_ARRIVED, metadata);
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.SCRIPTDATA_ARRIVED, function (data) {
+                            _this3._emitter.emit(_playerEvents2.default.SCRIPTDATA_ARRIVED, data);
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.STATISTICS_INFO, function (statInfo) {
+                            _this3._statisticsInfo = _this3._fillStatisticsInfo(statInfo);
+                            _this3._emitter.emit(_playerEvents2.default.STATISTICS_INFO, Object.assign({}, _this3._statisticsInfo));
+                        });
+                        this._transmuxer.on(_transmuxingEvents2.default.RECOMMEND_SEEKPOINT, function (milliseconds) {
+                            if (_this3._mediaElement && !_this3._config.accurateSeek) {
+                                _this3._requestSetTime = true;
+                                _this3._mediaElement.currentTime = milliseconds / 1000;
+                            }
+                        });
+
+                        this._transmuxer.open();
+                    }
+                }, {
+                    key: 'unload',
+                    value: function unload() {
+                        if (this._mediaElement) {
+                            this._mediaElement.pause();
+                        }
+                        if (this._msectl) {
+                            this._msectl.seek(0);
+                        }
+                        if (this._transmuxer) {
+                            this._transmuxer.close();
+                            this._transmuxer.destroy();
+                            this._transmuxer = null;
+                        }
+                    }
+                }, {
+                    key: 'play',
+                    value: function play() {
+                        return this._mediaElement.play();
+                    }
+                }, {
+                    key: 'pause',
+                    value: function pause() {
+                        this._mediaElement.pause();
+                    }
+                }, {
+                    key: '_fillStatisticsInfo',
+                    value: function _fillStatisticsInfo(statInfo) {
+                        statInfo.playerType = this._type;
+
+                        if (!(this._mediaElement instanceof HTMLVideoElement)) {
+                            return statInfo;
+                        }
+
+                        var hasQualityInfo = true;
+                        var decoded = 0;
+                        var dropped = 0;
+
+                        if (this._mediaElement.getVideoPlaybackQuality) {
+                            var quality = this._mediaElement.getVideoPlaybackQuality();
+                            decoded = quality.totalVideoFrames;
+                            dropped = quality.droppedVideoFrames;
+                        } else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
+                            decoded = this._mediaElement.webkitDecodedFrameCount;
+                            dropped = this._mediaElement.webkitDroppedFrameCount;
+                        } else {
+                            hasQualityInfo = false;
+                        }
+
+                        if (hasQualityInfo) {
+                            statInfo.decodedFrames = decoded;
+                            statInfo.droppedFrames = dropped;
+                        }
+
+                        return statInfo;
+                    }
+                }, {
+                    key: '_onmseUpdateEnd',
+                    value: function _onmseUpdateEnd() {
+                        if (!this._config.lazyLoad || this._config.isLive) {
+                            return;
+                        }
+
+                        var buffered = this._mediaElement.buffered;
+                        var currentTime = this._mediaElement.currentTime;
+                        var currentRangeStart = 0;
+                        var currentRangeEnd = 0;
+
+                        for (var i = 0; i < buffered.length; i++) {
+                            var start = buffered.start(i);
+                            var end = buffered.end(i);
+                            if (start <= currentTime && currentTime < end) {
+                                currentRangeStart = start;
+                                currentRangeEnd = end;
+                                break;
+                            }
+                        }
+
+                        if (currentRangeEnd >= currentTime + this._config.lazyLoadMaxDuration && this._progressChecker == null) {
+                            _logger2.default.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
+                            this._suspendTransmuxer();
+                        }
+                    }
+                }, {
+                    key: '_onmseBufferFull',
+                    value: function _onmseBufferFull() {
+                        _logger2.default.v(this.TAG, 'MSE SourceBuffer is full, suspend transmuxing task');
+                        if (this._progressChecker == null) {
+                            this._suspendTransmuxer();
+                        }
+                    }
+                }, {
+                    key: '_suspendTransmuxer',
+                    value: function _suspendTransmuxer() {
+                        if (this._transmuxer) {
+                            this._transmuxer.pause();
+
+                            if (this._progressChecker == null) {
+                                this._progressChecker = window.setInterval(this._checkProgressAndResume.bind(this), 1000);
+                            }
+                        }
+                    }
+                }, {
+                    key: '_checkProgressAndResume',
+                    value: function _checkProgressAndResume() {
+                        var currentTime = this._mediaElement.currentTime;
+                        var buffered = this._mediaElement.buffered;
+
+                        var needResume = false;
+
+                        for (var i = 0; i < buffered.length; i++) {
+                            var from = buffered.start(i);
+                            var to = buffered.end(i);
+                            if (currentTime >= from && currentTime < to) {
+                                if (currentTime >= to - this._config.lazyLoadRecoverDuration) {
+                                    needResume = true;
+                                }
+                                break;
+                            }
+                        }
+
+                        if (needResume) {
+                            window.clearInterval(this._progressChecker);
+                            this._progressChecker = null;
+                            if (needResume) {
+                                _logger2.default.v(this.TAG, 'Continue loading from paused position');
+                                this._transmuxer.resume();
+                            }
+                        }
+                    }
+                }, {
+                    key: '_isTimepointBuffered',
+                    value: function _isTimepointBuffered(seconds) {
+                        var buffered = this._mediaElement.buffered;
+
+                        for (var i = 0; i < buffered.length; i++) {
+                            var from = buffered.start(i);
+                            var to = buffered.end(i);
+                            if (seconds >= from && seconds < to) {
+                                return true;
+                            }
+                        }
+                        return false;
+                    }
+                }, {
+                    key: '_internalSeek',
+                    value: function _internalSeek(seconds) {
+                        var directSeek = this._isTimepointBuffered(seconds);
+
+                        var directSeekBegin = false;
+                        var directSeekBeginTime = 0;
+
+                        if (seconds < 1.0 && this._mediaElement.buffered.length > 0) {
+                            var videoBeginTime = this._mediaElement.buffered.start(0);
+                            if (videoBeginTime < 1.0 && seconds < videoBeginTime || _browser2.default.safari) {
+                                directSeekBegin = true;
+                                // also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
+                                directSeekBeginTime = _browser2.default.safari ? 0.1 : videoBeginTime;
+                            }
+                        }
+
+                        if (directSeekBegin) {
+                            // seek to video begin, set currentTime directly if beginPTS buffered
+                            this._requestSetTime = true;
+                            this._mediaElement.currentTime = directSeekBeginTime;
+                        } else if (directSeek) {
+                            // buffered position
+                            if (!this._alwaysSeekKeyframe) {
+                                this._requestSetTime = true;
+                                this._mediaElement.currentTime = seconds;
+                            } else {
+                                var idr = this._msectl.getNearestKeyframe(Math.floor(seconds * 1000));
+                                this._requestSetTime = true;
+                                if (idr != null) {
+                                    this._mediaElement.currentTime = idr.dts / 1000;
+                                } else {
+                                    this._mediaElement.currentTime = seconds;
+                                }
+                            }
+                            if (this._progressChecker != null) {
+                                this._checkProgressAndResume();
+                            }
+                        } else {
+                            if (this._progressChecker != null) {
+                                window.clearInterval(this._progressChecker);
+                                this._progressChecker = null;
+                            }
+                            this._msectl.seek(seconds);
+                            this._transmuxer.seek(Math.floor(seconds * 1000)); // in milliseconds
+                            // no need to set mediaElement.currentTime if non-accurateSeek,
+                            // just wait for the recommend_seekpoint callback
+                            if (this._config.accurateSeek) {
+                                this._requestSetTime = true;
+                                this._mediaElement.currentTime = seconds;
+                            }
+                        }
+                    }
+                }, {
+                    key: '_checkAndApplyUnbufferedSeekpoint',
+                    value: function _checkAndApplyUnbufferedSeekpoint() {
+                        if (this._seekpointRecord) {
+                            if (this._seekpointRecord.recordTime <= this._now() - 100) {
+                                var target = this._mediaElement.currentTime;
+                                this._seekpointRecord = null;
+                                if (!this._isTimepointBuffered(target)) {
+                                    if (this._progressChecker != null) {
+                                        window.clearTimeout(this._progressChecker);
+                                        this._progressChecker = null;
+                                    }
+                                    // .currentTime is consists with .buffered timestamp
+                                    // Chrome/Edge use DTS, while FireFox/Safari use PTS
+                                    this._msectl.seek(target);
+                                    this._transmuxer.seek(Math.floor(target * 1000));
+                                    // set currentTime if accurateSeek, or wait for recommend_seekpoint callback
+                                    if (this._config.accurateSeek) {
+                                        this._requestSetTime = true;
+                                        this._mediaElement.currentTime = target;
+                                    }
+                                }
+                            } else {
+                                window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50);
+                            }
+                        }
+                    }
+                }, {
+                    key: '_checkAndResumeStuckPlayback',
+                    value: function _checkAndResumeStuckPlayback(stalled) {
+                        var media = this._mediaElement;
+                        if (stalled || !this._receivedCanPlay || media.readyState < 2) {
+                            // HAVE_CURRENT_DATA
+                            var buffered = media.buffered;
+                            if (buffered.length > 0 && media.currentTime < buffered.start(0)) {
+                                _logger2.default.w(this.TAG, 'Playback seems stuck at ' + media.currentTime + ', seek to ' + buffered.start(0));
+                                this._requestSetTime = true;
+                                this._mediaElement.currentTime = buffered.start(0);
+                                this._mediaElement.removeEventListener('progress', this.e.onvProgress);
+                            }
+                        } else {
+                            // Playback didn't stuck, remove progress event listener
+                            this._mediaElement.removeEventListener('progress', this.e.onvProgress);
+                        }
+                    }
+                }, {
+                    key: '_onvLoadedMetadata',
+                    value: function _onvLoadedMetadata(e) {
+                        if (this._pendingSeekTime != null) {
+                            this._mediaElement.currentTime = this._pendingSeekTime;
+                            this._pendingSeekTime = null;
+                        }
+                    }
+                }, {
+                    key: '_onvSeeking',
+                    value: function _onvSeeking(e) {
+                        // handle seeking request from browser's progress bar
+                        var target = this._mediaElement.currentTime;
+                        var buffered = this._mediaElement.buffered;
+
+                        if (this._requestSetTime) {
+                            this._requestSetTime = false;
+                            return;
+                        }
+
+                        if (target < 1.0 && buffered.length > 0) {
+                            // seek to video begin, set currentTime directly if beginPTS buffered
+                            var videoBeginTime = buffered.start(0);
+                            if (videoBeginTime < 1.0 && target < videoBeginTime || _browser2.default.safari) {
+                                this._requestSetTime = true;
+                                // also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
+                                this._mediaElement.currentTime = _browser2.default.safari ? 0.1 : videoBeginTime;
+                                return;
+                            }
+                        }
+
+                        if (this._isTimepointBuffered(target)) {
+                            if (this._alwaysSeekKeyframe) {
+                                var idr = this._msectl.getNearestKeyframe(Math.floor(target * 1000));
+                                if (idr != null) {
+                                    this._requestSetTime = true;
+                                    this._mediaElement.currentTime = idr.dts / 1000;
+                                }
+                            }
+                            if (this._progressChecker != null) {
+                                this._checkProgressAndResume();
+                            }
+                            return;
+                        }
+
+                        this._seekpointRecord = {
+                            seekPoint: target,
+                            recordTime: this._now()
                         };
-                        silentFrames.push(frame);
-                        mdatBytes += frame.size;
-                        currentDts += refSampleDuration;
+                        window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50);
                     }
-
-                    // last frame: align end time to next frame dts
-                    var lastFrame = silentFrames[silentFrames.length - 1];
-                    lastFrame.duration = _dts + sampleDuration - lastFrame.dts;
-
-                    // silentFrames.forEach((frame) => {
-                    //     Log.w(this.TAG, `SilentAudio: dts: ${frame.dts}, duration: ${frame.duration}`);
-                    // });
-
-                    // Set correct sample duration for current frame
-                    sampleDuration = Math.round(refSampleDuration);
-                }
-
-                mp4Samples.push({
-                    dts: _dts,
-                    pts: _dts,
-                    cts: 0,
-                    unit: _sample.unit,
-                    size: _sample.unit.byteLength,
-                    duration: sampleDuration,
-                    originalDts: originalDts,
-                    flags: {
-                        isLeading: 0,
-                        dependsOn: 1,
-                        isDependedOn: 0,
-                        hasRedundancy: 0
+                }, {
+                    key: '_onvCanPlay',
+                    value: function _onvCanPlay(e) {
+                        this._receivedCanPlay = true;
+                        this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay);
                     }
-                });
-
-                if (needFillSilentFrames) {
-                    // Silent frames should be inserted after wrong-duration frame
-                    mp4Samples.push.apply(mp4Samples, silentFrames);
-                }
-            }
-
-            // allocate mdatbox
-            if (mpegRawTrack) {
-                // allocate for raw mpeg buffer
-                mdatbox = new Uint8Array(mdatBytes);
-            } else {
-                // allocate for fmp4 mdat box
-                mdatbox = new Uint8Array(mdatBytes);
-                // size field
-                mdatbox[0] = mdatBytes >>> 24 & 0xFF;
-                mdatbox[1] = mdatBytes >>> 16 & 0xFF;
-                mdatbox[2] = mdatBytes >>> 8 & 0xFF;
-                mdatbox[3] = mdatBytes & 0xFF;
-                // type field (fourCC)
-                mdatbox.set(_mp4Generator2.default.types.mdat, 4);
-            }
-
-            // Write samples into mdatbox
-            for (var _i = 0; _i < mp4Samples.length; _i++) {
-                var _unit = mp4Samples[_i].unit;
-                mdatbox.set(_unit, offset);
-                offset += _unit.byteLength;
-            }
-
-            var latest = mp4Samples[mp4Samples.length - 1];
-            lastDts = latest.dts + latest.duration;
-            this._audioNextDts = lastDts;
-
-            // fill media segment info & add to info list
-            var info = new _mediaSegmentInfo.MediaSegmentInfo();
-            info.beginDts = firstDts;
-            info.endDts = lastDts;
-            info.beginPts = firstDts;
-            info.endPts = lastDts;
-            info.originalBeginDts = mp4Samples[0].originalDts;
-            info.originalEndDts = latest.originalDts + latest.duration;
-            info.firstSample = new _mediaSegmentInfo.SampleInfo(mp4Samples[0].dts, mp4Samples[0].pts, mp4Samples[0].duration, mp4Samples[0].originalDts, false);
-            info.lastSample = new _mediaSegmentInfo.SampleInfo(latest.dts, latest.pts, latest.duration, latest.originalDts, false);
-            if (!this._isLive) {
-                this._audioSegmentInfoList.append(info);
-            }
-
-            track.samples = mp4Samples;
-            track.sequenceNumber++;
-
-            var moofbox = null;
-
-            if (mpegRawTrack) {
-                // Generate empty buffer, because useless for raw mpeg
-                moofbox = new Uint8Array();
-            } else {
-                // Generate moof for fmp4 segment
-                moofbox = _mp4Generator2.default.moof(track, firstDts);
-            }
-
-            track.samples = [];
-            track.length = 0;
-
-            var segment = {
-                type: 'audio',
-                data: this._mergeBoxes(moofbox, mdatbox).buffer,
-                sampleCount: mp4Samples.length,
-                info: info
-            };
-
-            if (mpegRawTrack && firstSegmentAfterSeek) {
-                // For MPEG audio stream in MSE, if seeking occurred, before appending new buffer
-                // We need explicitly set timestampOffset to the desired point in timeline for mpeg SourceBuffer.
-                segment.timestampOffset = firstDts;
-            }
-
-            this._onMediaSegment('audio', segment);
-        }
-    }, {
-        key: '_remuxVideo',
-        value: function _remuxVideo(videoTrack, force) {
-            if (this._videoMeta == null) {
-                return;
-            }
-
-            var track = videoTrack;
-            var samples = track.samples;
-            var dtsCorrection = undefined;
-            var firstDts = -1,
-                lastDts = -1;
-            var firstPts = -1,
-                lastPts = -1;
-
-            if (!samples || samples.length === 0) {
-                return;
-            }
-            if (samples.length === 1 && !force) {
-                // If [sample count in current batch] === 1 && (force != true)
-                // Ignore and keep in demuxer's queue
-                return;
-            } // else if (force === true) do remux
-
-            var offset = 8;
-            var mdatbox = null;
-            var mdatBytes = 8 + videoTrack.length;
-
-            var lastSample = null;
-
-            // Pop the lastSample and waiting for stash
-            if (samples.length > 1) {
-                lastSample = samples.pop();
-                mdatBytes -= lastSample.length;
-            }
-
-            // Insert [stashed lastSample in the previous batch] to the front
-            if (this._videoStashedLastSample != null) {
-                var sample = this._videoStashedLastSample;
-                this._videoStashedLastSample = null;
-                samples.unshift(sample);
-                mdatBytes += sample.length;
-            }
-
-            // Stash the lastSample of current batch, waiting for next batch
-            if (lastSample != null) {
-                this._videoStashedLastSample = lastSample;
-            }
-
-            var firstSampleOriginalDts = samples[0].dts - this._dtsBase;
-
-            // calculate dtsCorrection
-            if (this._videoNextDts) {
-                dtsCorrection = firstSampleOriginalDts - this._videoNextDts;
-            } else {
-                // this._videoNextDts == undefined
-                if (this._videoSegmentInfoList.isEmpty()) {
-                    dtsCorrection = 0;
-                } else {
-                    var _lastSample2 = this._videoSegmentInfoList.getLastSampleBefore(firstSampleOriginalDts);
-                    if (_lastSample2 != null) {
-                        var distance = firstSampleOriginalDts - (_lastSample2.originalDts + _lastSample2.duration);
-                        if (distance <= 3) {
-                            distance = 0;
+                }, {
+                    key: '_onvStalled',
+                    value: function _onvStalled(e) {
+                        this._checkAndResumeStuckPlayback(true);
+                    }
+                }, {
+                    key: '_onvProgress',
+                    value: function _onvProgress(e) {
+                        this._checkAndResumeStuckPlayback();
+                    }
+                }, {
+                    key: 'type',
+                    get: function get() {
+                        return this._type;
+                    }
+                }, {
+                    key: 'buffered',
+                    get: function get() {
+                        return this._mediaElement.buffered;
+                    }
+                }, {
+                    key: 'duration',
+                    get: function get() {
+                        return this._mediaElement.duration;
+                    }
+                }, {
+                    key: 'volume',
+                    get: function get() {
+                        return this._mediaElement.volume;
+                    },
+                    set: function set(value) {
+                        this._mediaElement.volume = value;
+                    }
+                }, {
+                    key: 'muted',
+                    get: function get() {
+                        return this._mediaElement.muted;
+                    },
+                    set: function set(muted) {
+                        this._mediaElement.muted = muted;
+                    }
+                }, {
+                    key: 'currentTime',
+                    get: function get() {
+                        if (this._mediaElement) {
+                            return this._mediaElement.currentTime;
                         }
-                        var expectedDts = _lastSample2.dts + _lastSample2.duration + distance;
-                        dtsCorrection = firstSampleOriginalDts - expectedDts;
-                    } else {
-                        // lastSample == null, cannot found
-                        dtsCorrection = 0;
+                        return 0;
+                    },
+                    set: function set(seconds) {
+                        if (this._mediaElement) {
+                            this._internalSeek(seconds);
+                        } else {
+                            this._pendingSeekTime = seconds;
+                        }
                     }
-                }
-            }
-
-            var info = new _mediaSegmentInfo.MediaSegmentInfo();
-            var mp4Samples = [];
-
-            // Correct dts for each sample, and calculate sample duration. Then output to mp4Samples
-            for (var i = 0; i < samples.length; i++) {
-                var _sample2 = samples[i];
-                var originalDts = _sample2.dts - this._dtsBase;
-                var isKeyframe = _sample2.isKeyframe;
-                var dts = originalDts - dtsCorrection;
-                var cts = _sample2.cts;
-                var pts = dts + cts;
-
-                if (firstDts === -1) {
-                    firstDts = dts;
-                    firstPts = pts;
-                }
-
-                var sampleDuration = 0;
-
-                if (i !== samples.length - 1) {
-                    var nextDts = samples[i + 1].dts - this._dtsBase - dtsCorrection;
-                    sampleDuration = nextDts - dts;
-                } else {
-                    // the last sample
-                    if (lastSample != null) {
-                        // use stashed sample's dts to calculate sample duration
-                        var _nextDts2 = lastSample.dts - this._dtsBase - dtsCorrection;
-                        sampleDuration = _nextDts2 - dts;
-                    } else if (mp4Samples.length >= 1) {
-                        // use second last sample duration
-                        sampleDuration = mp4Samples[mp4Samples.length - 1].duration;
-                    } else {
-                        // the only one sample, use reference sample duration
-                        sampleDuration = Math.floor(this._videoMeta.refSampleDuration);
+                }, {
+                    key: 'mediaInfo',
+                    get: function get() {
+                        return Object.assign({}, this._mediaInfo);
                     }
-                }
-
-                if (isKeyframe) {
-                    var syncPoint = new _mediaSegmentInfo.SampleInfo(dts, pts, sampleDuration, _sample2.dts, true);
-                    syncPoint.fileposition = _sample2.fileposition;
-                    info.appendSyncPoint(syncPoint);
-                }
-
-                mp4Samples.push({
-                    dts: dts,
-                    pts: pts,
-                    cts: cts,
-                    units: _sample2.units,
-                    size: _sample2.length,
-                    isKeyframe: isKeyframe,
-                    duration: sampleDuration,
-                    originalDts: originalDts,
-                    flags: {
-                        isLeading: 0,
-                        dependsOn: isKeyframe ? 2 : 1,
-                        isDependedOn: isKeyframe ? 1 : 0,
-                        hasRedundancy: 0,
-                        isNonSync: isKeyframe ? 0 : 1
+                }, {
+                    key: 'statisticsInfo',
+                    get: function get() {
+                        if (this._statisticsInfo == null) {
+                            this._statisticsInfo = {};
+                        }
+                        this._statisticsInfo = this._fillStatisticsInfo(this._statisticsInfo);
+                        return Object.assign({}, this._statisticsInfo);
                     }
-                });
-            }
+                }]);
 
-            // allocate mdatbox
-            mdatbox = new Uint8Array(mdatBytes);
-            mdatbox[0] = mdatBytes >>> 24 & 0xFF;
-            mdatbox[1] = mdatBytes >>> 16 & 0xFF;
-            mdatbox[2] = mdatBytes >>> 8 & 0xFF;
-            mdatbox[3] = mdatBytes & 0xFF;
-            mdatbox.set(_mp4Generator2.default.types.mdat, 4);
+                return FlvPlayer;
+            }();
 
-            // Write samples into mdatbox
-            for (var _i2 = 0; _i2 < mp4Samples.length; _i2++) {
-                var units = mp4Samples[_i2].units;
-                while (units.length) {
-                    var unit = units.shift();
-                    var data = unit.data;
-                    mdatbox.set(data, offset);
-                    offset += data.byteLength;
-                }
-            }
+            exports.default = FlvPlayer;
 
-            var latest = mp4Samples[mp4Samples.length - 1];
-            lastDts = latest.dts + latest.duration;
-            lastPts = latest.pts + latest.duration;
-            this._videoNextDts = lastDts;
+        }, { "../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) {
+            'use strict';
 
-            // fill media segment info & add to info list
-            info.beginDts = firstDts;
-            info.endDts = lastDts;
-            info.beginPts = firstPts;
-            info.endPts = lastPts;
-            info.originalBeginDts = mp4Samples[0].originalDts;
-            info.originalEndDts = latest.originalDts + latest.duration;
-            info.firstSample = new _mediaSegmentInfo.SampleInfo(mp4Samples[0].dts, mp4Samples[0].pts, mp4Samples[0].duration, mp4Samples[0].originalDts, mp4Samples[0].isKeyframe);
-            info.lastSample = new _mediaSegmentInfo.SampleInfo(latest.dts, latest.pts, latest.duration, latest.originalDts, latest.isKeyframe);
-            if (!this._isLive) {
-                this._videoSegmentInfoList.append(info);
-            }
-
-            track.samples = mp4Samples;
-            track.sequenceNumber++;
-
-            // workaround for chrome < 50: force first sample as a random access point
-            // see https://bugs.chromium.org/p/chromium/issues/detail?id=229412
-            if (this._forceFirstIDR) {
-                var flags = mp4Samples[0].flags;
-                flags.dependsOn = 2;
-                flags.isNonSync = 0;
-            }
-
-            var moofbox = _mp4Generator2.default.moof(track, firstDts);
-            track.samples = [];
-            track.length = 0;
-
-            this._onMediaSegment('video', {
-                type: 'video',
-                data: this._mergeBoxes(moofbox, mdatbox).buffer,
-                sampleCount: mp4Samples.length,
-                info: info
+            Object.defineProperty(exports, "__esModule", {
+                value: true
             });
-        }
-    }, {
-        key: '_mergeBoxes',
-        value: function _mergeBoxes(moof, mdat) {
-            var result = new Uint8Array(moof.byteLength + mdat.byteLength);
-            result.set(moof, 0);
-            result.set(mdat, moof.byteLength);
-            return result;
-        }
-    }, {
-        key: 'onInitSegment',
-        get: function get() {
-            return this._onInitSegment;
-        },
-        set: function set(callback) {
-            this._onInitSegment = callback;
-        }
 
-        /* prototype: function onMediaSegment(type: string, mediaSegment: MediaSegment): void
-           MediaSegment: {
-               type: string,
-               data: ArrayBuffer,
-               sampleCount: int32
-               info: MediaSegmentInfo
-           }
-        */
+            var _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; };
 
-    }, {
-        key: 'onMediaSegment',
-        get: function get() {
-            return this._onMediaSegment;
-        },
-        set: function set(callback) {
-            this._onMediaSegment = callback;
-        }
-    }]);
-
-    return MP4Remuxer;
-}();
-
-exports.default = MP4Remuxer;
-
-},{"../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){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var Browser = {};
-
-function detect() {
-    // modified from jquery-browser-plugin
-
-    var ua = self.navigator.userAgent.toLowerCase();
-
-    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) || [];
-
-    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) || [];
-
-    var matched = {
-        browser: match[5] || match[3] || match[1] || '',
-        version: match[2] || match[4] || '0',
-        majorVersion: match[4] || match[2] || '0',
-        platform: platform_match[0] || ''
-    };
-
-    var browser = {};
-    if (matched.browser) {
-        browser[matched.browser] = true;
-
-        var versionArray = matched.majorVersion.split('.');
-        browser.version = {
-            major: parseInt(matched.majorVersion, 10),
-            string: matched.version
-        };
-        if (versionArray.length > 1) {
-            browser.version.minor = parseInt(versionArray[1], 10);
-        }
-        if (versionArray.length > 2) {
-            browser.version.build = parseInt(versionArray[2], 10);
-        }
-    }
-
-    if (matched.platform) {
-        browser[matched.platform] = true;
-    }
-
-    if (browser.chrome || browser.opr || browser.safari) {
-        browser.webkit = true;
-    }
-
-    // MSIE. IE11 has 'rv' identifer
-    if (browser.rv || browser.iemobile) {
-        if (browser.rv) {
-            delete browser.rv;
-        }
-        var msie = 'msie';
-        matched.browser = msie;
-        browser[msie] = true;
-    }
-
-    // Microsoft Edge
-    if (browser.edge) {
-        delete browser.edge;
-        var msedge = 'msedge';
-        matched.browser = msedge;
-        browser[msedge] = true;
-    }
-
-    // Opera 15+
-    if (browser.opr) {
-        var opera = 'opera';
-        matched.browser = opera;
-        browser[opera] = true;
-    }
-
-    // Stock android browsers are marked as Safari
-    if (browser.safari && browser.android) {
-        var android = 'android';
-        matched.browser = android;
-        browser[android] = true;
-    }
-
-    browser.name = matched.browser;
-    browser.platform = matched.platform;
-
-    for (var key in Browser) {
-        if (Browser.hasOwnProperty(key)) {
-            delete Browser[key];
-        }
-    }
-    Object.assign(Browser, browser);
-}
-
-detect();
-
-exports.default = Browser;
-
-},{}],40:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }();
-
-function _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; }
-
-function _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; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var RuntimeException = exports.RuntimeException = function () {
-    function RuntimeException(message) {
-        _classCallCheck(this, RuntimeException);
-
-        this._message = message;
-    }
-
-    _createClass(RuntimeException, [{
-        key: 'toString',
-        value: function toString() {
-            return this.name + ': ' + this.message;
-        }
-    }, {
-        key: 'name',
-        get: function get() {
-            return 'RuntimeException';
-        }
-    }, {
-        key: 'message',
-        get: function get() {
-            return this._message;
-        }
-    }]);
-
-    return RuntimeException;
-}();
-
-var IllegalStateException = exports.IllegalStateException = function (_RuntimeException) {
-    _inherits(IllegalStateException, _RuntimeException);
-
-    function IllegalStateException(message) {
-        _classCallCheck(this, IllegalStateException);
-
-        return _possibleConstructorReturn(this, (IllegalStateException.__proto__ || Object.getPrototypeOf(IllegalStateException)).call(this, message));
-    }
-
-    _createClass(IllegalStateException, [{
-        key: 'name',
-        get: function get() {
-            return 'IllegalStateException';
-        }
-    }]);
-
-    return IllegalStateException;
-}(RuntimeException);
-
-var InvalidArgumentException = exports.InvalidArgumentException = function (_RuntimeException2) {
-    _inherits(InvalidArgumentException, _RuntimeException2);
-
-    function InvalidArgumentException(message) {
-        _classCallCheck(this, InvalidArgumentException);
-
-        return _possibleConstructorReturn(this, (InvalidArgumentException.__proto__ || Object.getPrototypeOf(InvalidArgumentException)).call(this, message));
-    }
-
-    _createClass(InvalidArgumentException, [{
-        key: 'name',
-        get: function get() {
-            return 'InvalidArgumentException';
-        }
-    }]);
-
-    return InvalidArgumentException;
-}(RuntimeException);
-
-var NotImplementedException = exports.NotImplementedException = function (_RuntimeException3) {
-    _inherits(NotImplementedException, _RuntimeException3);
-
-    function NotImplementedException(message) {
-        _classCallCheck(this, NotImplementedException);
-
-        return _possibleConstructorReturn(this, (NotImplementedException.__proto__ || Object.getPrototypeOf(NotImplementedException)).call(this, message));
-    }
-
-    _createClass(NotImplementedException, [{
-        key: 'name',
-        get: function get() {
-            return 'NotImplementedException';
-        }
-    }]);
-
-    return NotImplementedException;
-}(RuntimeException);
-
-},{}],41:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
+            var _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; }; }(); /*
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * Copyright (C) 2016 Bilibili. All Rights Reserved.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       *
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * @author zheng qian <xqq@xqq.im>
@@ -11558,499 +9579,2498 @@
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       * limitations under the License.
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       */
 
-var _events = _dereq_('events');
+            var _events = _dereq_('events');
 
-var _events2 = _interopRequireDefault(_events);
+            var _events2 = _interopRequireDefault(_events);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+            var _playerEvents = _dereq_('./player-events.js');
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+            var _playerEvents2 = _interopRequireDefault(_playerEvents);
 
-var Log = function () {
-    function Log() {
-        _classCallCheck(this, Log);
-    }
+            var _config = _dereq_('../config.js');
 
-    _createClass(Log, null, [{
-        key: 'e',
-        value: function e(tag, msg) {
-            if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
+            var _exception = _dereq_('../utils/exception.js');
 
-            var str = '[' + tag + '] > ' + msg;
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-            if (Log.ENABLE_CALLBACK) {
-                Log.emitter.emit('log', 'error', str);
-            }
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-            if (!Log.ENABLE_ERROR) {
-                return;
-            }
+            // Player wrapper for browser's native player (HTMLVideoElement) without MediaSource src. 
+            var NativePlayer = function () {
+                function NativePlayer(mediaDataSource, config) {
+                    _classCallCheck(this, NativePlayer);
 
-            if (console.error) {
-                console.error(str);
-            } else if (console.warn) {
-                console.warn(str);
-            } else {
-                console.log(str);
-            }
-        }
-    }, {
-        key: 'i',
-        value: function i(tag, msg) {
-            if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
+                    this.TAG = 'NativePlayer';
+                    this._type = 'NativePlayer';
+                    this._emitter = new _events2.default();
 
-            var str = '[' + tag + '] > ' + msg;
+                    this._config = (0, _config.createDefaultConfig)();
+                    if ((typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object') {
+                        Object.assign(this._config, config);
+                    }
 
-            if (Log.ENABLE_CALLBACK) {
-                Log.emitter.emit('log', 'info', str);
-            }
+                    if (mediaDataSource.type.toLowerCase() === 'flv') {
+                        throw new _exception.InvalidArgumentException('NativePlayer does\'t support flv MediaDataSource input!');
+                    }
+                    if (mediaDataSource.hasOwnProperty('segments')) {
+                        throw new _exception.InvalidArgumentException('NativePlayer(' + mediaDataSource.type + ') doesn\'t support multipart playback!');
+                    }
 
-            if (!Log.ENABLE_INFO) {
-                return;
-            }
+                    this.e = {
+                        onvLoadedMetadata: this._onvLoadedMetadata.bind(this)
+                    };
 
-            if (console.info) {
-                console.info(str);
-            } else {
-                console.log(str);
-            }
-        }
-    }, {
-        key: 'w',
-        value: function w(tag, msg) {
-            if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
+                    this._pendingSeekTime = null;
+                    this._statisticsReporter = null;
 
-            var str = '[' + tag + '] > ' + msg;
-
-            if (Log.ENABLE_CALLBACK) {
-                Log.emitter.emit('log', 'warn', str);
-            }
-
-            if (!Log.ENABLE_WARN) {
-                return;
-            }
-
-            if (console.warn) {
-                console.warn(str);
-            } else {
-                console.log(str);
-            }
-        }
-    }, {
-        key: 'd',
-        value: function d(tag, msg) {
-            if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
-
-            var str = '[' + tag + '] > ' + msg;
-
-            if (Log.ENABLE_CALLBACK) {
-                Log.emitter.emit('log', 'debug', str);
-            }
-
-            if (!Log.ENABLE_DEBUG) {
-                return;
-            }
-
-            if (console.debug) {
-                console.debug(str);
-            } else {
-                console.log(str);
-            }
-        }
-    }, {
-        key: 'v',
-        value: function v(tag, msg) {
-            if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
-
-            var str = '[' + tag + '] > ' + msg;
-
-            if (Log.ENABLE_CALLBACK) {
-                Log.emitter.emit('log', 'verbose', str);
-            }
-
-            if (!Log.ENABLE_VERBOSE) {
-                return;
-            }
-
-            console.log(str);
-        }
-    }]);
-
-    return Log;
-}();
-
-Log.GLOBAL_TAG = 'flv.js';
-Log.FORCE_GLOBAL_TAG = false;
-Log.ENABLE_ERROR = true;
-Log.ENABLE_INFO = true;
-Log.ENABLE_WARN = true;
-Log.ENABLE_DEBUG = true;
-Log.ENABLE_VERBOSE = true;
-
-Log.ENABLE_CALLBACK = false;
-
-Log.emitter = new _events2.default();
-
-exports.default = Log;
-
-},{"events":2}],42:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }(); /*
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
-
-var _events = _dereq_('events');
-
-var _events2 = _interopRequireDefault(_events);
-
-var _logger = _dereq_('./logger.js');
-
-var _logger2 = _interopRequireDefault(_logger);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-var LoggingControl = function () {
-    function LoggingControl() {
-        _classCallCheck(this, LoggingControl);
-    }
-
-    _createClass(LoggingControl, null, [{
-        key: 'getConfig',
-        value: function getConfig() {
-            return {
-                globalTag: _logger2.default.GLOBAL_TAG,
-                forceGlobalTag: _logger2.default.FORCE_GLOBAL_TAG,
-                enableVerbose: _logger2.default.ENABLE_VERBOSE,
-                enableDebug: _logger2.default.ENABLE_DEBUG,
-                enableInfo: _logger2.default.ENABLE_INFO,
-                enableWarn: _logger2.default.ENABLE_WARN,
-                enableError: _logger2.default.ENABLE_ERROR,
-                enableCallback: _logger2.default.ENABLE_CALLBACK
-            };
-        }
-    }, {
-        key: 'applyConfig',
-        value: function applyConfig(config) {
-            _logger2.default.GLOBAL_TAG = config.globalTag;
-            _logger2.default.FORCE_GLOBAL_TAG = config.forceGlobalTag;
-            _logger2.default.ENABLE_VERBOSE = config.enableVerbose;
-            _logger2.default.ENABLE_DEBUG = config.enableDebug;
-            _logger2.default.ENABLE_INFO = config.enableInfo;
-            _logger2.default.ENABLE_WARN = config.enableWarn;
-            _logger2.default.ENABLE_ERROR = config.enableError;
-            _logger2.default.ENABLE_CALLBACK = config.enableCallback;
-        }
-    }, {
-        key: '_notifyChange',
-        value: function _notifyChange() {
-            var emitter = LoggingControl.emitter;
-
-            if (emitter.listenerCount('change') > 0) {
-                var config = LoggingControl.getConfig();
-                emitter.emit('change', config);
-            }
-        }
-    }, {
-        key: 'registerListener',
-        value: function registerListener(listener) {
-            LoggingControl.emitter.addListener('change', listener);
-        }
-    }, {
-        key: 'removeListener',
-        value: function removeListener(listener) {
-            LoggingControl.emitter.removeListener('change', listener);
-        }
-    }, {
-        key: 'addLogListener',
-        value: function addLogListener(listener) {
-            _logger2.default.emitter.addListener('log', listener);
-            if (_logger2.default.emitter.listenerCount('log') > 0) {
-                _logger2.default.ENABLE_CALLBACK = true;
-                LoggingControl._notifyChange();
-            }
-        }
-    }, {
-        key: 'removeLogListener',
-        value: function removeLogListener(listener) {
-            _logger2.default.emitter.removeListener('log', listener);
-            if (_logger2.default.emitter.listenerCount('log') === 0) {
-                _logger2.default.ENABLE_CALLBACK = false;
-                LoggingControl._notifyChange();
-            }
-        }
-    }, {
-        key: 'forceGlobalTag',
-        get: function get() {
-            return _logger2.default.FORCE_GLOBAL_TAG;
-        },
-        set: function set(enable) {
-            _logger2.default.FORCE_GLOBAL_TAG = enable;
-            LoggingControl._notifyChange();
-        }
-    }, {
-        key: 'globalTag',
-        get: function get() {
-            return _logger2.default.GLOBAL_TAG;
-        },
-        set: function set(tag) {
-            _logger2.default.GLOBAL_TAG = tag;
-            LoggingControl._notifyChange();
-        }
-    }, {
-        key: 'enableAll',
-        get: function get() {
-            return _logger2.default.ENABLE_VERBOSE && _logger2.default.ENABLE_DEBUG && _logger2.default.ENABLE_INFO && _logger2.default.ENABLE_WARN && _logger2.default.ENABLE_ERROR;
-        },
-        set: function set(enable) {
-            _logger2.default.ENABLE_VERBOSE = enable;
-            _logger2.default.ENABLE_DEBUG = enable;
-            _logger2.default.ENABLE_INFO = enable;
-            _logger2.default.ENABLE_WARN = enable;
-            _logger2.default.ENABLE_ERROR = enable;
-            LoggingControl._notifyChange();
-        }
-    }, {
-        key: 'enableDebug',
-        get: function get() {
-            return _logger2.default.ENABLE_DEBUG;
-        },
-        set: function set(enable) {
-            _logger2.default.ENABLE_DEBUG = enable;
-            LoggingControl._notifyChange();
-        }
-    }, {
-        key: 'enableVerbose',
-        get: function get() {
-            return _logger2.default.ENABLE_VERBOSE;
-        },
-        set: function set(enable) {
-            _logger2.default.ENABLE_VERBOSE = enable;
-            LoggingControl._notifyChange();
-        }
-    }, {
-        key: 'enableInfo',
-        get: function get() {
-            return _logger2.default.ENABLE_INFO;
-        },
-        set: function set(enable) {
-            _logger2.default.ENABLE_INFO = enable;
-            LoggingControl._notifyChange();
-        }
-    }, {
-        key: 'enableWarn',
-        get: function get() {
-            return _logger2.default.ENABLE_WARN;
-        },
-        set: function set(enable) {
-            _logger2.default.ENABLE_WARN = enable;
-            LoggingControl._notifyChange();
-        }
-    }, {
-        key: 'enableError',
-        get: function get() {
-            return _logger2.default.ENABLE_ERROR;
-        },
-        set: function set(enable) {
-            _logger2.default.ENABLE_ERROR = enable;
-            LoggingControl._notifyChange();
-        }
-    }]);
-
-    return LoggingControl;
-}();
-
-LoggingControl.emitter = new _events2.default();
-
-exports.default = LoggingControl;
-
-},{"./logger.js":41,"events":2}],43:[function(_dereq_,module,exports){
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-
-var _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; }; }();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var Polyfill = function () {
-    function Polyfill() {
-        _classCallCheck(this, Polyfill);
-    }
-
-    _createClass(Polyfill, null, [{
-        key: 'install',
-        value: function install() {
-            // ES6 Object.setPrototypeOf
-            Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
-                obj.__proto__ = proto;
-                return obj;
-            };
-
-            // ES6 Object.assign
-            Object.assign = Object.assign || function (target) {
-                if (target === undefined || target === null) {
-                    throw new TypeError('Cannot convert undefined or null to object');
+                    this._mediaDataSource = mediaDataSource;
+                    this._mediaElement = null;
                 }
 
-                var output = Object(target);
-                for (var i = 1; i < arguments.length; i++) {
-                    var source = arguments[i];
-                    if (source !== undefined && source !== null) {
-                        for (var key in source) {
-                            if (source.hasOwnProperty(key)) {
-                                output[key] = source[key];
+                _createClass(NativePlayer, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        if (this._mediaElement) {
+                            this.unload();
+                            this.detachMediaElement();
+                        }
+                        this.e = null;
+                        this._mediaDataSource = null;
+                        this._emitter.removeAllListeners();
+                        this._emitter = null;
+                    }
+                }, {
+                    key: 'on',
+                    value: function on(event, listener) {
+                        var _this = this;
+
+                        if (event === _playerEvents2.default.MEDIA_INFO) {
+                            if (this._mediaElement != null && this._mediaElement.readyState !== 0) {
+                                // HAVE_NOTHING
+                                Promise.resolve().then(function () {
+                                    _this._emitter.emit(_playerEvents2.default.MEDIA_INFO, _this.mediaInfo);
+                                });
+                            }
+                        } else if (event === _playerEvents2.default.STATISTICS_INFO) {
+                            if (this._mediaElement != null && this._mediaElement.readyState !== 0) {
+                                Promise.resolve().then(function () {
+                                    _this._emitter.emit(_playerEvents2.default.STATISTICS_INFO, _this.statisticsInfo);
+                                });
+                            }
+                        }
+                        this._emitter.addListener(event, listener);
+                    }
+                }, {
+                    key: 'off',
+                    value: function off(event, listener) {
+                        this._emitter.removeListener(event, listener);
+                    }
+                }, {
+                    key: 'attachMediaElement',
+                    value: function attachMediaElement(mediaElement) {
+                        this._mediaElement = mediaElement;
+                        mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata);
+
+                        if (this._pendingSeekTime != null) {
+                            try {
+                                mediaElement.currentTime = this._pendingSeekTime;
+                                this._pendingSeekTime = null;
+                            } catch (e) {
+                                // IE11 may throw InvalidStateError if readyState === 0
+                                // Defer set currentTime operation after loadedmetadata
                             }
                         }
                     }
-                }
-                return output;
+                }, {
+                    key: 'detachMediaElement',
+                    value: function detachMediaElement() {
+                        if (this._mediaElement) {
+                            this._mediaElement.src = '';
+                            this._mediaElement.removeAttribute('src');
+                            this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
+                            this._mediaElement = null;
+                        }
+                        if (this._statisticsReporter != null) {
+                            window.clearInterval(this._statisticsReporter);
+                            this._statisticsReporter = null;
+                        }
+                    }
+                }, {
+                    key: 'load',
+                    value: function load() {
+                        if (!this._mediaElement) {
+                            throw new _exception.IllegalStateException('HTMLMediaElement must be attached before load()!');
+                        }
+                        this._mediaElement.src = this._mediaDataSource.url;
+
+                        if (this._mediaElement.readyState > 0) {
+                            this._mediaElement.currentTime = 0;
+                        }
+
+                        this._mediaElement.preload = 'auto';
+                        this._mediaElement.load();
+                        this._statisticsReporter = window.setInterval(this._reportStatisticsInfo.bind(this), this._config.statisticsInfoReportInterval);
+                    }
+                }, {
+                    key: 'unload',
+                    value: function unload() {
+                        if (this._mediaElement) {
+                            this._mediaElement.src = '';
+                            this._mediaElement.removeAttribute('src');
+                        }
+                        if (this._statisticsReporter != null) {
+                            window.clearInterval(this._statisticsReporter);
+                            this._statisticsReporter = null;
+                        }
+                    }
+                }, {
+                    key: 'play',
+                    value: function play() {
+                        return this._mediaElement.play();
+                    }
+                }, {
+                    key: 'pause',
+                    value: function pause() {
+                        this._mediaElement.pause();
+                    }
+                }, {
+                    key: '_onvLoadedMetadata',
+                    value: function _onvLoadedMetadata(e) {
+                        if (this._pendingSeekTime != null) {
+                            this._mediaElement.currentTime = this._pendingSeekTime;
+                            this._pendingSeekTime = null;
+                        }
+                        this._emitter.emit(_playerEvents2.default.MEDIA_INFO, this.mediaInfo);
+                    }
+                }, {
+                    key: '_reportStatisticsInfo',
+                    value: function _reportStatisticsInfo() {
+                        this._emitter.emit(_playerEvents2.default.STATISTICS_INFO, this.statisticsInfo);
+                    }
+                }, {
+                    key: 'type',
+                    get: function get() {
+                        return this._type;
+                    }
+                }, {
+                    key: 'buffered',
+                    get: function get() {
+                        return this._mediaElement.buffered;
+                    }
+                }, {
+                    key: 'duration',
+                    get: function get() {
+                        return this._mediaElement.duration;
+                    }
+                }, {
+                    key: 'volume',
+                    get: function get() {
+                        return this._mediaElement.volume;
+                    },
+                    set: function set(value) {
+                        this._mediaElement.volume = value;
+                    }
+                }, {
+                    key: 'muted',
+                    get: function get() {
+                        return this._mediaElement.muted;
+                    },
+                    set: function set(muted) {
+                        this._mediaElement.muted = muted;
+                    }
+                }, {
+                    key: 'currentTime',
+                    get: function get() {
+                        if (this._mediaElement) {
+                            return this._mediaElement.currentTime;
+                        }
+                        return 0;
+                    },
+                    set: function set(seconds) {
+                        if (this._mediaElement) {
+                            this._mediaElement.currentTime = seconds;
+                        } else {
+                            this._pendingSeekTime = seconds;
+                        }
+                    }
+                }, {
+                    key: 'mediaInfo',
+                    get: function get() {
+                        var mediaPrefix = this._mediaElement instanceof HTMLAudioElement ? 'audio/' : 'video/';
+                        var info = {
+                            mimeType: mediaPrefix + this._mediaDataSource.type
+                        };
+                        if (this._mediaElement) {
+                            info.duration = Math.floor(this._mediaElement.duration * 1000);
+                            if (this._mediaElement instanceof HTMLVideoElement) {
+                                info.width = this._mediaElement.videoWidth;
+                                info.height = this._mediaElement.videoHeight;
+                            }
+                        }
+                        return info;
+                    }
+                }, {
+                    key: 'statisticsInfo',
+                    get: function get() {
+                        var info = {
+                            playerType: this._type,
+                            url: this._mediaDataSource.url
+                        };
+
+                        if (!(this._mediaElement instanceof HTMLVideoElement)) {
+                            return info;
+                        }
+
+                        var hasQualityInfo = true;
+                        var decoded = 0;
+                        var dropped = 0;
+
+                        if (this._mediaElement.getVideoPlaybackQuality) {
+                            var quality = this._mediaElement.getVideoPlaybackQuality();
+                            decoded = quality.totalVideoFrames;
+                            dropped = quality.droppedVideoFrames;
+                        } else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
+                            decoded = this._mediaElement.webkitDecodedFrameCount;
+                            dropped = this._mediaElement.webkitDroppedFrameCount;
+                        } else {
+                            hasQualityInfo = false;
+                        }
+
+                        if (hasQualityInfo) {
+                            info.decodedFrames = decoded;
+                            info.droppedFrames = dropped;
+                        }
+
+                        return info;
+                    }
+                }]);
+
+                return NativePlayer;
+            }();
+
+            exports.default = NativePlayer;
+
+        }, { "../config.js": 5, "../utils/exception.js": 40, "./player-events.js": 35, "events": 2 }], 34: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+            exports.ErrorDetails = exports.ErrorTypes = undefined;
+
+            var _loader = _dereq_('../io/loader.js');
+
+            var _demuxErrors = _dereq_('../demux/demux-errors.js');
+
+            var _demuxErrors2 = _interopRequireDefault(_demuxErrors);
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var ErrorTypes = exports.ErrorTypes = {
+                NETWORK_ERROR: 'NetworkError',
+                MEDIA_ERROR: 'MediaError',
+                OTHER_ERROR: 'OtherError'
             };
 
-            // ES6 Promise (missing support in IE11)
-            if (typeof self.Promise !== 'function') {
-                _dereq_('es6-promise').polyfill();
+            var ErrorDetails = exports.ErrorDetails = {
+                NETWORK_EXCEPTION: _loader.LoaderErrors.EXCEPTION,
+                NETWORK_STATUS_CODE_INVALID: _loader.LoaderErrors.HTTP_STATUS_CODE_INVALID,
+                NETWORK_TIMEOUT: _loader.LoaderErrors.CONNECTING_TIMEOUT,
+                NETWORK_UNRECOVERABLE_EARLY_EOF: _loader.LoaderErrors.UNRECOVERABLE_EARLY_EOF,
+
+                MEDIA_MSE_ERROR: 'MediaMSEError',
+
+                MEDIA_FORMAT_ERROR: _demuxErrors2.default.FORMAT_ERROR,
+                MEDIA_FORMAT_UNSUPPORTED: _demuxErrors2.default.FORMAT_UNSUPPORTED,
+                MEDIA_CODEC_UNSUPPORTED: _demuxErrors2.default.CODEC_UNSUPPORTED
+            };
+
+        }, { "../demux/demux-errors.js": 16, "../io/loader.js": 24 }], 35: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var PlayerEvents = {
+                ERROR: 'error',
+                LOADING_COMPLETE: 'loading_complete',
+                RECOVERED_EARLY_EOF: 'recovered_early_eof',
+                MEDIA_INFO: 'media_info',
+                METADATA_ARRIVED: 'metadata_arrived',
+                SCRIPTDATA_ARRIVED: 'scriptdata_arrived',
+                STATISTICS_INFO: 'statistics_info'
+            };
+
+            exports.default = PlayerEvents;
+
+        }, {}], 36: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }();
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * This file is modified from dailymotion's hls.js library (hls.js/src/helper/aac.js)
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var AAC = function () {
+                function AAC() {
+                    _classCallCheck(this, AAC);
+                }
+
+                _createClass(AAC, null, [{
+                    key: 'getSilentFrame',
+                    value: function getSilentFrame(codec, channelCount) {
+                        if (codec === 'mp4a.40.2') {
+                            // handle LC-AAC
+                            if (channelCount === 1) {
+                                return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x23, 0x80]);
+                            } else if (channelCount === 2) {
+                                return new Uint8Array([0x21, 0x00, 0x49, 0x90, 0x02, 0x19, 0x00, 0x23, 0x80]);
+                            } else if (channelCount === 3) {
+                                return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x8e]);
+                            } else if (channelCount === 4) {
+                                return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x80, 0x2c, 0x80, 0x08, 0x02, 0x38]);
+                            } else if (channelCount === 5) {
+                                return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x82, 0x30, 0x04, 0x99, 0x00, 0x21, 0x90, 0x02, 0x38]);
+                            } else if (channelCount === 6) {
+                                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]);
+                            }
+                        } else {
+                            // handle HE-AAC (mp4a.40.5 / mp4a.40.29)
+                            if (channelCount === 1) {
+                                // 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
+                                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]);
+                            } else if (channelCount === 2) {
+                                // 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
+                                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]);
+                            } else if (channelCount === 3) {
+                                // 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
+                                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]);
+                            }
+                        }
+                        return null;
+                    }
+                }]);
+
+                return AAC;
+            }();
+
+            exports.default = AAC;
+
+        }, {}], 37: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }();
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * This file is derived from dailymotion's hls.js library (hls.js/src/remux/mp4-generator.js)
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            //  MP4 boxes generator for ISO BMFF (ISO Base Media File Format, defined in ISO/IEC 14496-12)
+            var MP4 = function () {
+                function MP4() {
+                    _classCallCheck(this, MP4);
+                }
+
+                _createClass(MP4, null, [{
+                    key: 'init',
+                    value: function init() {
+                        MP4.types = {
+                            avc1: [], avcC: [], btrt: [], dinf: [],
+                            dref: [], esds: [], ftyp: [], hdlr: [],
+                            mdat: [], mdhd: [], mdia: [], mfhd: [],
+                            minf: [], moof: [], moov: [], mp4a: [],
+                            mvex: [], mvhd: [], sdtp: [], stbl: [],
+                            stco: [], stsc: [], stsd: [], stsz: [],
+                            stts: [], tfdt: [], tfhd: [], traf: [],
+                            trak: [], trun: [], trex: [], tkhd: [],
+                            vmhd: [], smhd: [], '.mp3': []
+                        };
+
+                        for (var name in MP4.types) {
+                            if (MP4.types.hasOwnProperty(name)) {
+                                MP4.types[name] = [name.charCodeAt(0), name.charCodeAt(1), name.charCodeAt(2), name.charCodeAt(3)];
+                            }
+                        }
+
+                        var constants = MP4.constants = {};
+
+                        constants.FTYP = new Uint8Array([0x69, 0x73, 0x6F, 0x6D, // major_brand: isom
+                            0x0, 0x0, 0x0, 0x1, // minor_version: 0x01
+                            0x69, 0x73, 0x6F, 0x6D, // isom
+                            0x61, 0x76, 0x63, 0x31 // avc1
+                        ]);
+
+                        constants.STSD_PREFIX = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x01 // entry_count
+                        ]);
+
+                        constants.STTS = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x00 // entry_count
+                        ]);
+
+                        constants.STSC = constants.STCO = constants.STTS;
+
+                        constants.STSZ = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x00, // sample_size
+                            0x00, 0x00, 0x00, 0x00 // sample_count
+                        ]);
+
+                        constants.HDLR_VIDEO = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x00, // pre_defined
+                            0x76, 0x69, 0x64, 0x65, // handler_type: 'vide'
+                            0x00, 0x00, 0x00, 0x00, // reserved: 3 * 4 bytes
+                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x69, 0x64, 0x65, 0x6F, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00 // name: VideoHandler
+                        ]);
+
+                        constants.HDLR_AUDIO = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x00, // pre_defined
+                            0x73, 0x6F, 0x75, 0x6E, // handler_type: 'soun'
+                            0x00, 0x00, 0x00, 0x00, // reserved: 3 * 4 bytes
+                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x6F, 0x75, 0x6E, 0x64, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00 // name: SoundHandler
+                        ]);
+
+                        constants.DREF = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x01, // entry_count
+                            0x00, 0x00, 0x00, 0x0C, // entry_size
+                            0x75, 0x72, 0x6C, 0x20, // type 'url '
+                            0x00, 0x00, 0x00, 0x01 // version(0) + flags
+                        ]);
+
+                        // Sound media header
+                        constants.SMHD = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x00 // balance(2) + reserved(2)
+                        ]);
+
+                        // video media header
+                        constants.VMHD = new Uint8Array([0x00, 0x00, 0x00, 0x01, // version(0) + flags
+                            0x00, 0x00, // graphicsmode: 2 bytes
+                            0x00, 0x00, 0x00, 0x00, // opcolor: 3 * 2 bytes
+                            0x00, 0x00]);
+                    }
+
+                    // Generate a box
+
+                }, {
+                    key: 'box',
+                    value: function box(type) {
+                        var size = 8;
+                        var result = null;
+                        var datas = Array.prototype.slice.call(arguments, 1);
+                        var arrayCount = datas.length;
+
+                        for (var i = 0; i < arrayCount; i++) {
+                            size += datas[i].byteLength;
+                        }
+
+                        result = new Uint8Array(size);
+                        result[0] = size >>> 24 & 0xFF; // size
+                        result[1] = size >>> 16 & 0xFF;
+                        result[2] = size >>> 8 & 0xFF;
+                        result[3] = size & 0xFF;
+
+                        result.set(type, 4); // type
+
+                        var offset = 8;
+                        for (var _i = 0; _i < arrayCount; _i++) {
+                            // data body
+                            result.set(datas[_i], offset);
+                            offset += datas[_i].byteLength;
+                        }
+
+                        return result;
+                    }
+
+                    // emit ftyp & moov
+
+                }, {
+                    key: 'generateInitSegment',
+                    value: function generateInitSegment(meta) {
+                        var ftyp = MP4.box(MP4.types.ftyp, MP4.constants.FTYP);
+                        var moov = MP4.moov(meta);
+
+                        var result = new Uint8Array(ftyp.byteLength + moov.byteLength);
+                        result.set(ftyp, 0);
+                        result.set(moov, ftyp.byteLength);
+                        return result;
+                    }
+
+                    // Movie metadata box
+
+                }, {
+                    key: 'moov',
+                    value: function moov(meta) {
+                        var mvhd = MP4.mvhd(meta.timescale, meta.duration);
+                        var trak = MP4.trak(meta);
+                        var mvex = MP4.mvex(meta);
+                        return MP4.box(MP4.types.moov, mvhd, trak, mvex);
+                    }
+
+                    // Movie header box
+
+                }, {
+                    key: 'mvhd',
+                    value: function mvhd(timescale, duration) {
+                        return MP4.box(MP4.types.mvhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x00, // creation_time
+                            0x00, 0x00, 0x00, 0x00, // modification_time
+                            timescale >>> 24 & 0xFF, // timescale: 4 bytes
+                            timescale >>> 16 & 0xFF, timescale >>> 8 & 0xFF, timescale & 0xFF, duration >>> 24 & 0xFF, // duration: 4 bytes
+                            duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, 0x00, 0x01, 0x00, 0x00, // Preferred rate: 1.0
+                            0x01, 0x00, 0x00, 0x00, // PreferredVolume(1.0, 2bytes) + reserved(2bytes)
+                            0x00, 0x00, 0x00, 0x00, // reserved: 4 + 4 bytes
+                            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // ----begin composition matrix----
+                            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----
+                            0x00, 0x00, 0x00, 0x00, // ----begin pre_defined 6 * 4 bytes----
+                            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----
+                            0xFF, 0xFF, 0xFF, 0xFF // next_track_ID
+                        ]));
+                    }
+
+                    // Track box
+
+                }, {
+                    key: 'trak',
+                    value: function trak(meta) {
+                        return MP4.box(MP4.types.trak, MP4.tkhd(meta), MP4.mdia(meta));
+                    }
+
+                    // Track header box
+
+                }, {
+                    key: 'tkhd',
+                    value: function tkhd(meta) {
+                        var trackId = meta.id,
+                            duration = meta.duration;
+                        var width = meta.presentWidth,
+                            height = meta.presentHeight;
+
+                        return MP4.box(MP4.types.tkhd, new Uint8Array([0x00, 0x00, 0x00, 0x07, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x00, // creation_time
+                            0x00, 0x00, 0x00, 0x00, // modification_time
+                            trackId >>> 24 & 0xFF, // track_ID: 4 bytes
+                            trackId >>> 16 & 0xFF, trackId >>> 8 & 0xFF, trackId & 0xFF, 0x00, 0x00, 0x00, 0x00, // reserved: 4 bytes
+                            duration >>> 24 & 0xFF, // duration: 4 bytes
+                            duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, 0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
+                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // layer(2bytes) + alternate_group(2bytes)
+                            0x00, 0x00, 0x00, 0x00, // volume(2bytes) + reserved(2bytes)
+                            0x00, 0x01, 0x00, 0x00, // ----begin composition matrix----
+                            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----
+                            width >>> 8 & 0xFF, // width and height
+                            width & 0xFF, 0x00, 0x00, height >>> 8 & 0xFF, height & 0xFF, 0x00, 0x00]));
+                    }
+
+                    // Media Box
+
+                }, {
+                    key: 'mdia',
+                    value: function mdia(meta) {
+                        return MP4.box(MP4.types.mdia, MP4.mdhd(meta), MP4.hdlr(meta), MP4.minf(meta));
+                    }
+
+                    // Media header box
+
+                }, {
+                    key: 'mdhd',
+                    value: function mdhd(meta) {
+                        var timescale = meta.timescale;
+                        var duration = meta.duration;
+                        return MP4.box(MP4.types.mdhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            0x00, 0x00, 0x00, 0x00, // creation_time
+                            0x00, 0x00, 0x00, 0x00, // modification_time
+                            timescale >>> 24 & 0xFF, // timescale: 4 bytes
+                            timescale >>> 16 & 0xFF, timescale >>> 8 & 0xFF, timescale & 0xFF, duration >>> 24 & 0xFF, // duration: 4 bytes
+                            duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, 0x55, 0xC4, // language: und (undetermined)
+                            0x00, 0x00 // pre_defined = 0
+                        ]));
+                    }
+
+                    // Media handler reference box
+
+                }, {
+                    key: 'hdlr',
+                    value: function hdlr(meta) {
+                        var data = null;
+                        if (meta.type === 'audio') {
+                            data = MP4.constants.HDLR_AUDIO;
+                        } else {
+                            data = MP4.constants.HDLR_VIDEO;
+                        }
+                        return MP4.box(MP4.types.hdlr, data);
+                    }
+
+                    // Media infomation box
+
+                }, {
+                    key: 'minf',
+                    value: function minf(meta) {
+                        var xmhd = null;
+                        if (meta.type === 'audio') {
+                            xmhd = MP4.box(MP4.types.smhd, MP4.constants.SMHD);
+                        } else {
+                            xmhd = MP4.box(MP4.types.vmhd, MP4.constants.VMHD);
+                        }
+                        return MP4.box(MP4.types.minf, xmhd, MP4.dinf(), MP4.stbl(meta));
+                    }
+
+                    // Data infomation box
+
+                }, {
+                    key: 'dinf',
+                    value: function dinf() {
+                        var result = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, MP4.constants.DREF));
+                        return result;
+                    }
+
+                    // Sample table box
+
+                }, {
+                    key: 'stbl',
+                    value: function stbl(meta) {
+                        var result = MP4.box(MP4.types.stbl, // type: stbl
+                            MP4.stsd(meta), // Sample Description Table
+                            MP4.box(MP4.types.stts, MP4.constants.STTS), // Time-To-Sample
+                            MP4.box(MP4.types.stsc, MP4.constants.STSC), // Sample-To-Chunk
+                            MP4.box(MP4.types.stsz, MP4.constants.STSZ), // Sample size
+                            MP4.box(MP4.types.stco, MP4.constants.STCO // Chunk offset
+                            ));
+                        return result;
+                    }
+
+                    // Sample description box
+
+                }, {
+                    key: 'stsd',
+                    value: function stsd(meta) {
+                        if (meta.type === 'audio') {
+                            if (meta.codec === 'mp3') {
+                                return MP4.box(MP4.types.stsd, MP4.constants.STSD_PREFIX, MP4.mp3(meta));
+                            }
+                            // else: aac -> mp4a
+                            return MP4.box(MP4.types.stsd, MP4.constants.STSD_PREFIX, MP4.mp4a(meta));
+                        } else {
+                            return MP4.box(MP4.types.stsd, MP4.constants.STSD_PREFIX, MP4.avc1(meta));
+                        }
+                    }
+                }, {
+                    key: 'mp3',
+                    value: function mp3(meta) {
+                        var channelCount = meta.channelCount;
+                        var sampleRate = meta.audioSampleRate;
+
+                        var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // reserved(4)
+                            0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
+                            0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
+                            0x00, 0x00, 0x00, 0x00, 0x00, channelCount, // channelCount(2)
+                            0x00, 0x10, // sampleSize(2)
+                            0x00, 0x00, 0x00, 0x00, // reserved(4)
+                            sampleRate >>> 8 & 0xFF, // Audio sample rate
+                            sampleRate & 0xFF, 0x00, 0x00]);
+
+                        return MP4.box(MP4.types['.mp3'], data);
+                    }
+                }, {
+                    key: 'mp4a',
+                    value: function mp4a(meta) {
+                        var channelCount = meta.channelCount;
+                        var sampleRate = meta.audioSampleRate;
+
+                        var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // reserved(4)
+                            0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
+                            0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
+                            0x00, 0x00, 0x00, 0x00, 0x00, channelCount, // channelCount(2)
+                            0x00, 0x10, // sampleSize(2)
+                            0x00, 0x00, 0x00, 0x00, // reserved(4)
+                            sampleRate >>> 8 & 0xFF, // Audio sample rate
+                            sampleRate & 0xFF, 0x00, 0x00]);
+
+                        return MP4.box(MP4.types.mp4a, data, MP4.esds(meta));
+                    }
+                }, {
+                    key: 'esds',
+                    value: function esds(meta) {
+                        var config = meta.config || [];
+                        var configSize = config.length;
+                        var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version 0 + flags
+
+                            0x03, // descriptor_type
+                            0x17 + configSize, // length3
+                            0x00, 0x01, // es_id
+                            0x00, // stream_priority
+
+                            0x04, // descriptor_type
+                            0x0F + configSize, // length
+                            0x40, // codec: mpeg4_audio
+                            0x15, // stream_type: Audio
+                            0x00, 0x00, 0x00, // buffer_size
+                            0x00, 0x00, 0x00, 0x00, // maxBitrate
+                            0x00, 0x00, 0x00, 0x00, // avgBitrate
+
+                            0x05 // descriptor_type
+                        ].concat([configSize]).concat(config).concat([0x06, 0x01, 0x02 // GASpecificConfig
+                        ]));
+                        return MP4.box(MP4.types.esds, data);
+                    }
+                }, {
+                    key: 'avc1',
+                    value: function avc1(meta) {
+                        var avcc = meta.avcc;
+                        var width = meta.codecWidth,
+                            height = meta.codecHeight;
+
+                        var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // reserved(4)
+                            0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
+                            0x00, 0x00, 0x00, 0x00, // pre_defined(2) + reserved(2)
+                            0x00, 0x00, 0x00, 0x00, // pre_defined: 3 * 4 bytes
+                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, width >>> 8 & 0xFF, // width: 2 bytes
+                            width & 0xFF, height >>> 8 & 0xFF, // height: 2 bytes
+                            height & 0xFF, 0x00, 0x48, 0x00, 0x00, // horizresolution: 4 bytes
+                            0x00, 0x48, 0x00, 0x00, // vertresolution: 4 bytes
+                            0x00, 0x00, 0x00, 0x00, // reserved: 4 bytes
+                            0x00, 0x01, // frame_count
+                            0x0A, // strlen
+                            0x78, 0x71, 0x71, 0x2F, // compressorname: 32 bytes
+                            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
+                            0xFF, 0xFF // pre_defined = -1
+                        ]);
+                        return MP4.box(MP4.types.avc1, data, MP4.box(MP4.types.avcC, avcc));
+                    }
+
+                    // Movie Extends box
+
+                }, {
+                    key: 'mvex',
+                    value: function mvex(meta) {
+                        return MP4.box(MP4.types.mvex, MP4.trex(meta));
+                    }
+
+                    // Track Extends box
+
+                }, {
+                    key: 'trex',
+                    value: function trex(meta) {
+                        var trackId = meta.id;
+                        var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) + flags
+                            trackId >>> 24 & 0xFF, // track_ID
+                            trackId >>> 16 & 0xFF, trackId >>> 8 & 0xFF, trackId & 0xFF, 0x00, 0x00, 0x00, 0x01, // default_sample_description_index
+                            0x00, 0x00, 0x00, 0x00, // default_sample_duration
+                            0x00, 0x00, 0x00, 0x00, // default_sample_size
+                            0x00, 0x01, 0x00, 0x01 // default_sample_flags
+                        ]);
+                        return MP4.box(MP4.types.trex, data);
+                    }
+
+                    // Movie fragment box
+
+                }, {
+                    key: 'moof',
+                    value: function moof(track, baseMediaDecodeTime) {
+                        return MP4.box(MP4.types.moof, MP4.mfhd(track.sequenceNumber), MP4.traf(track, baseMediaDecodeTime));
+                    }
+                }, {
+                    key: 'mfhd',
+                    value: function mfhd(sequenceNumber) {
+                        var data = new Uint8Array([0x00, 0x00, 0x00, 0x00, sequenceNumber >>> 24 & 0xFF, // sequence_number: int32
+                            sequenceNumber >>> 16 & 0xFF, sequenceNumber >>> 8 & 0xFF, sequenceNumber & 0xFF]);
+                        return MP4.box(MP4.types.mfhd, data);
+                    }
+
+                    // Track fragment box
+
+                }, {
+                    key: 'traf',
+                    value: function traf(track, baseMediaDecodeTime) {
+                        var trackId = track.id;
+
+                        // Track fragment header box
+                        var tfhd = MP4.box(MP4.types.tfhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) & flags
+                            trackId >>> 24 & 0xFF, // track_ID
+                            trackId >>> 16 & 0xFF, trackId >>> 8 & 0xFF, trackId & 0xFF]));
+                        // Track Fragment Decode Time
+                        var tfdt = MP4.box(MP4.types.tfdt, new Uint8Array([0x00, 0x00, 0x00, 0x00, // version(0) & flags
+                            baseMediaDecodeTime >>> 24 & 0xFF, // baseMediaDecodeTime: int32
+                            baseMediaDecodeTime >>> 16 & 0xFF, baseMediaDecodeTime >>> 8 & 0xFF, baseMediaDecodeTime & 0xFF]));
+                        var sdtp = MP4.sdtp(track);
+                        var trun = MP4.trun(track, sdtp.byteLength + 16 + 16 + 8 + 16 + 8 + 8);
+
+                        return MP4.box(MP4.types.traf, tfhd, tfdt, trun, sdtp);
+                    }
+
+                    // Sample Dependency Type box
+
+                }, {
+                    key: 'sdtp',
+                    value: function sdtp(track) {
+                        var samples = track.samples || [];
+                        var sampleCount = samples.length;
+                        var data = new Uint8Array(4 + sampleCount);
+                        // 0~4 bytes: version(0) & flags
+                        for (var i = 0; i < sampleCount; i++) {
+                            var flags = samples[i].flags;
+                            data[i + 4] = flags.isLeading << 6 | // is_leading: 2 (bit)
+                                flags.dependsOn << 4 // sample_depends_on
+                                | flags.isDependedOn << 2 // sample_is_depended_on
+                                | flags.hasRedundancy; // sample_has_redundancy
+                        }
+                        return MP4.box(MP4.types.sdtp, data);
+                    }
+
+                    // Track fragment run box
+
+                }, {
+                    key: 'trun',
+                    value: function trun(track, offset) {
+                        var samples = track.samples || [];
+                        var sampleCount = samples.length;
+                        var dataSize = 12 + 16 * sampleCount;
+                        var data = new Uint8Array(dataSize);
+                        offset += 8 + dataSize;
+
+                        data.set([0x00, 0x00, 0x0F, 0x01, // version(0) & flags
+                            sampleCount >>> 24 & 0xFF, // sample_count
+                            sampleCount >>> 16 & 0xFF, sampleCount >>> 8 & 0xFF, sampleCount & 0xFF, offset >>> 24 & 0xFF, // data_offset
+                            offset >>> 16 & 0xFF, offset >>> 8 & 0xFF, offset & 0xFF], 0);
+
+                        for (var i = 0; i < sampleCount; i++) {
+                            var duration = samples[i].duration;
+                            var size = samples[i].size;
+                            var flags = samples[i].flags;
+                            var cts = samples[i].cts;
+                            data.set([duration >>> 24 & 0xFF, // sample_duration
+                            duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, size >>> 24 & 0xFF, // sample_size
+                            size >>> 16 & 0xFF, size >>> 8 & 0xFF, size & 0xFF, flags.isLeading << 2 | flags.dependsOn, // sample_flags
+                            flags.isDependedOn << 6 | flags.hasRedundancy << 4 | flags.isNonSync, 0x00, 0x00, // sample_degradation_priority
+                            cts >>> 24 & 0xFF, // sample_composition_time_offset
+                            cts >>> 16 & 0xFF, cts >>> 8 & 0xFF, cts & 0xFF], 12 + 16 * i);
+                        }
+                        return MP4.box(MP4.types.trun, data);
+                    }
+                }, {
+                    key: 'mdat',
+                    value: function mdat(data) {
+                        return MP4.box(MP4.types.mdat, data);
+                    }
+                }]);
+
+                return MP4;
+            }();
+
+            MP4.init();
+
+            exports.default = MP4;
+
+        }, {}], 38: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }(); /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
+
+            var _logger = _dereq_('../utils/logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            var _mp4Generator = _dereq_('./mp4-generator.js');
+
+            var _mp4Generator2 = _interopRequireDefault(_mp4Generator);
+
+            var _aacSilent = _dereq_('./aac-silent.js');
+
+            var _aacSilent2 = _interopRequireDefault(_aacSilent);
+
+            var _browser = _dereq_('../utils/browser.js');
+
+            var _browser2 = _interopRequireDefault(_browser);
+
+            var _mediaSegmentInfo = _dereq_('../core/media-segment-info.js');
+
+            var _exception = _dereq_('../utils/exception.js');
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            // Fragmented mp4 remuxer
+            var MP4Remuxer = function () {
+                function MP4Remuxer(config) {
+                    _classCallCheck(this, MP4Remuxer);
+
+                    this.TAG = 'MP4Remuxer';
+
+                    this._config = config;
+                    this._isLive = config.isLive === true ? true : false;
+
+                    this._dtsBase = -1;
+                    this._dtsBaseInited = false;
+                    this._audioDtsBase = Infinity;
+                    this._videoDtsBase = Infinity;
+                    this._audioNextDts = undefined;
+                    this._videoNextDts = undefined;
+                    this._audioStashedLastSample = null;
+                    this._videoStashedLastSample = null;
+
+                    this._audioMeta = null;
+                    this._videoMeta = null;
+
+                    this._audioSegmentInfoList = new _mediaSegmentInfo.MediaSegmentInfoList('audio');
+                    this._videoSegmentInfoList = new _mediaSegmentInfo.MediaSegmentInfoList('video');
+
+                    this._onInitSegment = null;
+                    this._onMediaSegment = null;
+
+                    // Workaround for chrome < 50: Always force first sample as a Random Access Point in media segment
+                    // see https://bugs.chromium.org/p/chromium/issues/detail?id=229412
+                    this._forceFirstIDR = _browser2.default.chrome && (_browser2.default.version.major < 50 || _browser2.default.version.major === 50 && _browser2.default.version.build < 2661) ? true : false;
+
+                    // Workaround for IE11/Edge: Fill silent aac frame after keyframe-seeking
+                    // Make audio beginDts equals with video beginDts, in order to fix seek freeze
+                    this._fillSilentAfterSeek = _browser2.default.msedge || _browser2.default.msie;
+
+                    // While only FireFox supports 'audio/mp4, codecs="mp3"', use 'audio/mpeg' for chrome, safari, ...
+                    this._mp3UseMpegAudio = !_browser2.default.firefox;
+
+                    this._fillAudioTimestampGap = this._config.fixAudioTimestampGap;
+                }
+
+                _createClass(MP4Remuxer, [{
+                    key: 'destroy',
+                    value: function destroy() {
+                        this._dtsBase = -1;
+                        this._dtsBaseInited = false;
+                        this._audioMeta = null;
+                        this._videoMeta = null;
+                        this._audioSegmentInfoList.clear();
+                        this._audioSegmentInfoList = null;
+                        this._videoSegmentInfoList.clear();
+                        this._videoSegmentInfoList = null;
+                        this._onInitSegment = null;
+                        this._onMediaSegment = null;
+                    }
+                }, {
+                    key: 'bindDataSource',
+                    value: function bindDataSource(producer) {
+                        producer.onDataAvailable = this.remux.bind(this);
+                        producer.onTrackMetadata = this._onTrackMetadataReceived.bind(this);
+                        return this;
+                    }
+
+                    /* prototype: function onInitSegment(type: string, initSegment: ArrayBuffer): void
+                       InitSegment: {
+                           type: string,
+                           data: ArrayBuffer,
+                           codec: string,
+                           container: string
+                       }
+                    */
+
+                }, {
+                    key: 'insertDiscontinuity',
+                    value: function insertDiscontinuity() {
+                        this._audioNextDts = this._videoNextDts = undefined;
+                    }
+                }, {
+                    key: 'seek',
+                    value: function seek(originalDts) {
+                        this._audioStashedLastSample = null;
+                        this._videoStashedLastSample = null;
+                        this._videoSegmentInfoList.clear();
+                        this._audioSegmentInfoList.clear();
+                    }
+                }, {
+                    key: 'remux',
+                    value: function remux(audioTrack, videoTrack) {
+                        if (!this._onMediaSegment) {
+                            throw new _exception.IllegalStateException('MP4Remuxer: onMediaSegment callback must be specificed!');
+                        }
+                        if (!this._dtsBaseInited) {
+                            this._calculateDtsBase(audioTrack, videoTrack);
+                        }
+                        this._remuxVideo(videoTrack);
+                        this._remuxAudio(audioTrack);
+                    }
+                }, {
+                    key: '_onTrackMetadataReceived',
+                    value: function _onTrackMetadataReceived(type, metadata) {
+                        var metabox = null;
+
+                        var container = 'mp4';
+                        var codec = metadata.codec;
+
+                        if (type === 'audio') {
+                            this._audioMeta = metadata;
+                            if (metadata.codec === 'mp3' && this._mp3UseMpegAudio) {
+                                // 'audio/mpeg' for MP3 audio track
+                                container = 'mpeg';
+                                codec = '';
+                                metabox = new Uint8Array();
+                            } else {
+                                // 'audio/mp4, codecs="codec"'
+                                metabox = _mp4Generator2.default.generateInitSegment(metadata);
+                            }
+                        } else if (type === 'video') {
+                            this._videoMeta = metadata;
+                            metabox = _mp4Generator2.default.generateInitSegment(metadata);
+                        } else {
+                            return;
+                        }
+
+                        // dispatch metabox (Initialization Segment)
+                        if (!this._onInitSegment) {
+                            throw new _exception.IllegalStateException('MP4Remuxer: onInitSegment callback must be specified!');
+                        }
+                        this._onInitSegment(type, {
+                            type: type,
+                            data: metabox.buffer,
+                            codec: codec,
+                            container: type + '/' + container,
+                            mediaDuration: metadata.duration // in timescale 1000 (milliseconds)
+                        });
+                    }
+                }, {
+                    key: '_calculateDtsBase',
+                    value: function _calculateDtsBase(audioTrack, videoTrack) {
+                        if (this._dtsBaseInited) {
+                            return;
+                        }
+
+                        if (audioTrack.samples && audioTrack.samples.length) {
+                            this._audioDtsBase = audioTrack.samples[0].dts;
+                        }
+                        if (videoTrack.samples && videoTrack.samples.length) {
+                            this._videoDtsBase = videoTrack.samples[0].dts;
+                        }
+
+                        this._dtsBase = Math.min(this._audioDtsBase, this._videoDtsBase);
+                        this._dtsBaseInited = true;
+                    }
+                }, {
+                    key: 'flushStashedSamples',
+                    value: function flushStashedSamples() {
+                        var videoSample = this._videoStashedLastSample;
+                        var audioSample = this._audioStashedLastSample;
+
+                        var videoTrack = {
+                            type: 'video',
+                            id: 1,
+                            sequenceNumber: 0,
+                            samples: [],
+                            length: 0
+                        };
+
+                        if (videoSample != null) {
+                            videoTrack.samples.push(videoSample);
+                            videoTrack.length = videoSample.length;
+                        }
+
+                        var audioTrack = {
+                            type: 'audio',
+                            id: 2,
+                            sequenceNumber: 0,
+                            samples: [],
+                            length: 0
+                        };
+
+                        if (audioSample != null) {
+                            audioTrack.samples.push(audioSample);
+                            audioTrack.length = audioSample.length;
+                        }
+
+                        this._videoStashedLastSample = null;
+                        this._audioStashedLastSample = null;
+
+                        this._remuxVideo(videoTrack, true);
+                        this._remuxAudio(audioTrack, true);
+                    }
+                }, {
+                    key: '_remuxAudio',
+                    value: function _remuxAudio(audioTrack, force) {
+                        if (this._audioMeta == null) {
+                            return;
+                        }
+
+                        var track = audioTrack;
+                        var samples = track.samples;
+                        var dtsCorrection = undefined;
+                        var firstDts = -1,
+                            lastDts = -1,
+                            lastPts = -1;
+                        var refSampleDuration = this._audioMeta.refSampleDuration;
+
+                        var mpegRawTrack = this._audioMeta.codec === 'mp3' && this._mp3UseMpegAudio;
+                        var firstSegmentAfterSeek = this._dtsBaseInited && this._audioNextDts === undefined;
+
+                        var insertPrefixSilentFrame = false;
+
+                        if (!samples || samples.length === 0) {
+                            return;
+                        }
+                        if (samples.length === 1 && !force) {
+                            // If [sample count in current batch] === 1 && (force != true)
+                            // Ignore and keep in demuxer's queue
+                            return;
+                        } // else if (force === true) do remux
+
+                        var offset = 0;
+                        var mdatbox = null;
+                        var mdatBytes = 0;
+
+                        // calculate initial mdat size
+                        if (mpegRawTrack) {
+                            // for raw mpeg buffer
+                            offset = 0;
+                            mdatBytes = track.length;
+                        } else {
+                            // for fmp4 mdat box
+                            offset = 8; // size + type
+                            mdatBytes = 8 + track.length;
+                        }
+
+                        var lastSample = null;
+
+                        // Pop the lastSample and waiting for stash
+                        if (samples.length > 1) {
+                            lastSample = samples.pop();
+                            mdatBytes -= lastSample.length;
+                        }
+
+                        // Insert [stashed lastSample in the previous batch] to the front
+                        if (this._audioStashedLastSample != null) {
+                            var sample = this._audioStashedLastSample;
+                            this._audioStashedLastSample = null;
+                            samples.unshift(sample);
+                            mdatBytes += sample.length;
+                        }
+
+                        // Stash the lastSample of current batch, waiting for next batch
+                        if (lastSample != null) {
+                            this._audioStashedLastSample = lastSample;
+                        }
+
+                        var firstSampleOriginalDts = samples[0].dts - this._dtsBase;
+
+                        // calculate dtsCorrection
+                        if (this._audioNextDts) {
+                            dtsCorrection = firstSampleOriginalDts - this._audioNextDts;
+                        } else {
+                            // this._audioNextDts == undefined
+                            if (this._audioSegmentInfoList.isEmpty()) {
+                                dtsCorrection = 0;
+                                if (this._fillSilentAfterSeek && !this._videoSegmentInfoList.isEmpty()) {
+                                    if (this._audioMeta.originalCodec !== 'mp3') {
+                                        insertPrefixSilentFrame = true;
+                                    }
+                                }
+                            } else {
+                                var _lastSample = this._audioSegmentInfoList.getLastSampleBefore(firstSampleOriginalDts);
+                                if (_lastSample != null) {
+                                    var distance = firstSampleOriginalDts - (_lastSample.originalDts + _lastSample.duration);
+                                    if (distance <= 3) {
+                                        distance = 0;
+                                    }
+                                    var expectedDts = _lastSample.dts + _lastSample.duration + distance;
+                                    dtsCorrection = firstSampleOriginalDts - expectedDts;
+                                } else {
+                                    // lastSample == null, cannot found
+                                    dtsCorrection = 0;
+                                }
+                            }
+                        }
+
+                        if (insertPrefixSilentFrame) {
+                            // align audio segment beginDts to match with current video segment's beginDts
+                            var firstSampleDts = firstSampleOriginalDts - dtsCorrection;
+                            var videoSegment = this._videoSegmentInfoList.getLastSegmentBefore(firstSampleOriginalDts);
+                            if (videoSegment != null && videoSegment.beginDts < firstSampleDts) {
+                                var silentUnit = _aacSilent2.default.getSilentFrame(this._audioMeta.originalCodec, this._audioMeta.channelCount);
+                                if (silentUnit) {
+                                    var dts = videoSegment.beginDts;
+                                    var silentFrameDuration = firstSampleDts - videoSegment.beginDts;
+                                    _logger2.default.v(this.TAG, 'InsertPrefixSilentAudio: dts: ' + dts + ', duration: ' + silentFrameDuration);
+                                    samples.unshift({ unit: silentUnit, dts: dts, pts: dts });
+                                    mdatBytes += silentUnit.byteLength;
+                                } // silentUnit == null: Cannot generate, skip
+                            } else {
+                                insertPrefixSilentFrame = false;
+                            }
+                        }
+
+                        var mp4Samples = [];
+
+                        // Correct dts for each sample, and calculate sample duration. Then output to mp4Samples
+                        for (var i = 0; i < samples.length; i++) {
+                            var _sample = samples[i];
+                            var unit = _sample.unit;
+                            var originalDts = _sample.dts - this._dtsBase;
+                            var _dts = originalDts - dtsCorrection;
+
+                            if (firstDts === -1) {
+                                firstDts = _dts;
+                            }
+
+                            var sampleDuration = 0;
+
+                            if (i !== samples.length - 1) {
+                                var nextDts = samples[i + 1].dts - this._dtsBase - dtsCorrection;
+                                sampleDuration = nextDts - _dts;
+                            } else {
+                                // the last sample
+                                if (lastSample != null) {
+                                    // use stashed sample's dts to calculate sample duration
+                                    var _nextDts = lastSample.dts - this._dtsBase - dtsCorrection;
+                                    sampleDuration = _nextDts - _dts;
+                                } else if (mp4Samples.length >= 1) {
+                                    // use second last sample duration
+                                    sampleDuration = mp4Samples[mp4Samples.length - 1].duration;
+                                } else {
+                                    // the only one sample, use reference sample duration
+                                    sampleDuration = Math.floor(refSampleDuration);
+                                }
+                            }
+
+                            var needFillSilentFrames = false;
+                            var silentFrames = null;
+
+                            // Silent frame generation, if large timestamp gap detected && config.fixAudioTimestampGap
+                            if (sampleDuration > refSampleDuration * 1.5 && this._audioMeta.codec !== 'mp3' && this._fillAudioTimestampGap && !_browser2.default.safari) {
+                                // We need to insert silent frames to fill timestamp gap
+                                needFillSilentFrames = true;
+                                var delta = Math.abs(sampleDuration - refSampleDuration);
+                                var frameCount = Math.ceil(delta / refSampleDuration);
+                                var currentDts = _dts + refSampleDuration; // Notice: in float
+
+                                _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'));
+
+                                var _silentUnit = _aacSilent2.default.getSilentFrame(this._audioMeta.originalCodec, this._audioMeta.channelCount);
+                                if (_silentUnit == null) {
+                                    _logger2.default.w(this.TAG, 'Unable to generate silent frame for ' + (this._audioMeta.originalCodec + ' with ' + this._audioMeta.channelCount + ' channels, repeat last frame'));
+                                    // Repeat last frame
+                                    _silentUnit = unit;
+                                }
+                                silentFrames = [];
+
+                                for (var j = 0; j < frameCount; j++) {
+                                    var intDts = Math.round(currentDts); // round to integer
+                                    if (silentFrames.length > 0) {
+                                        // Set previous frame sample duration
+                                        var previousFrame = silentFrames[silentFrames.length - 1];
+                                        previousFrame.duration = intDts - previousFrame.dts;
+                                    }
+                                    var frame = {
+                                        dts: intDts,
+                                        pts: intDts,
+                                        cts: 0,
+                                        unit: _silentUnit,
+                                        size: _silentUnit.byteLength,
+                                        duration: 0, // wait for next sample
+                                        originalDts: originalDts,
+                                        flags: {
+                                            isLeading: 0,
+                                            dependsOn: 1,
+                                            isDependedOn: 0,
+                                            hasRedundancy: 0
+                                        }
+                                    };
+                                    silentFrames.push(frame);
+                                    mdatBytes += frame.size;
+                                    currentDts += refSampleDuration;
+                                }
+
+                                // last frame: align end time to next frame dts
+                                var lastFrame = silentFrames[silentFrames.length - 1];
+                                lastFrame.duration = _dts + sampleDuration - lastFrame.dts;
+
+                                // silentFrames.forEach((frame) => {
+                                //     Log.w(this.TAG, `SilentAudio: dts: ${frame.dts}, duration: ${frame.duration}`);
+                                // });
+
+                                // Set correct sample duration for current frame
+                                sampleDuration = Math.round(refSampleDuration);
+                            }
+
+                            mp4Samples.push({
+                                dts: _dts,
+                                pts: _dts,
+                                cts: 0,
+                                unit: _sample.unit,
+                                size: _sample.unit.byteLength,
+                                duration: sampleDuration,
+                                originalDts: originalDts,
+                                flags: {
+                                    isLeading: 0,
+                                    dependsOn: 1,
+                                    isDependedOn: 0,
+                                    hasRedundancy: 0
+                                }
+                            });
+
+                            if (needFillSilentFrames) {
+                                // Silent frames should be inserted after wrong-duration frame
+                                mp4Samples.push.apply(mp4Samples, silentFrames);
+                            }
+                        }
+
+                        // allocate mdatbox
+                        if (mpegRawTrack) {
+                            // allocate for raw mpeg buffer
+                            mdatbox = new Uint8Array(mdatBytes);
+                        } else {
+                            // allocate for fmp4 mdat box
+                            mdatbox = new Uint8Array(mdatBytes);
+                            // size field
+                            mdatbox[0] = mdatBytes >>> 24 & 0xFF;
+                            mdatbox[1] = mdatBytes >>> 16 & 0xFF;
+                            mdatbox[2] = mdatBytes >>> 8 & 0xFF;
+                            mdatbox[3] = mdatBytes & 0xFF;
+                            // type field (fourCC)
+                            mdatbox.set(_mp4Generator2.default.types.mdat, 4);
+                        }
+
+                        // Write samples into mdatbox
+                        for (var _i = 0; _i < mp4Samples.length; _i++) {
+                            var _unit = mp4Samples[_i].unit;
+                            mdatbox.set(_unit, offset);
+                            offset += _unit.byteLength;
+                        }
+
+                        var latest = mp4Samples[mp4Samples.length - 1];
+                        lastDts = latest.dts + latest.duration;
+                        this._audioNextDts = lastDts;
+
+                        // fill media segment info & add to info list
+                        var info = new _mediaSegmentInfo.MediaSegmentInfo();
+                        info.beginDts = firstDts;
+                        info.endDts = lastDts;
+                        info.beginPts = firstDts;
+                        info.endPts = lastDts;
+                        info.originalBeginDts = mp4Samples[0].originalDts;
+                        info.originalEndDts = latest.originalDts + latest.duration;
+                        info.firstSample = new _mediaSegmentInfo.SampleInfo(mp4Samples[0].dts, mp4Samples[0].pts, mp4Samples[0].duration, mp4Samples[0].originalDts, false);
+                        info.lastSample = new _mediaSegmentInfo.SampleInfo(latest.dts, latest.pts, latest.duration, latest.originalDts, false);
+                        if (!this._isLive) {
+                            this._audioSegmentInfoList.append(info);
+                        }
+
+                        track.samples = mp4Samples;
+                        track.sequenceNumber++;
+
+                        var moofbox = null;
+
+                        if (mpegRawTrack) {
+                            // Generate empty buffer, because useless for raw mpeg
+                            moofbox = new Uint8Array();
+                        } else {
+                            // Generate moof for fmp4 segment
+                            moofbox = _mp4Generator2.default.moof(track, firstDts);
+                        }
+
+                        track.samples = [];
+                        track.length = 0;
+
+                        var segment = {
+                            type: 'audio',
+                            data: this._mergeBoxes(moofbox, mdatbox).buffer,
+                            sampleCount: mp4Samples.length,
+                            info: info
+                        };
+
+                        if (mpegRawTrack && firstSegmentAfterSeek) {
+                            // For MPEG audio stream in MSE, if seeking occurred, before appending new buffer
+                            // We need explicitly set timestampOffset to the desired point in timeline for mpeg SourceBuffer.
+                            segment.timestampOffset = firstDts;
+                        }
+
+                        this._onMediaSegment('audio', segment);
+                    }
+                }, {
+                    key: '_remuxVideo',
+                    value: function _remuxVideo(videoTrack, force) {
+                        if (this._videoMeta == null) {
+                            return;
+                        }
+
+                        var track = videoTrack;
+                        var samples = track.samples;
+                        var dtsCorrection = undefined;
+                        var firstDts = -1,
+                            lastDts = -1;
+                        var firstPts = -1,
+                            lastPts = -1;
+
+                        if (!samples || samples.length === 0) {
+                            return;
+                        }
+                        if (samples.length === 1 && !force) {
+                            // If [sample count in current batch] === 1 && (force != true)
+                            // Ignore and keep in demuxer's queue
+                            return;
+                        } // else if (force === true) do remux
+
+                        var offset = 8;
+                        var mdatbox = null;
+                        var mdatBytes = 8 + videoTrack.length;
+
+                        var lastSample = null;
+
+                        // Pop the lastSample and waiting for stash
+                        if (samples.length > 1) {
+                            lastSample = samples.pop();
+                            mdatBytes -= lastSample.length;
+                        }
+
+                        // Insert [stashed lastSample in the previous batch] to the front
+                        if (this._videoStashedLastSample != null) {
+                            var sample = this._videoStashedLastSample;
+                            this._videoStashedLastSample = null;
+                            samples.unshift(sample);
+                            mdatBytes += sample.length;
+                        }
+
+                        // Stash the lastSample of current batch, waiting for next batch
+                        if (lastSample != null) {
+                            this._videoStashedLastSample = lastSample;
+                        }
+
+                        var firstSampleOriginalDts = samples[0].dts - this._dtsBase;
+
+                        // calculate dtsCorrection
+                        if (this._videoNextDts) {
+                            dtsCorrection = firstSampleOriginalDts - this._videoNextDts;
+                        } else {
+                            // this._videoNextDts == undefined
+                            if (this._videoSegmentInfoList.isEmpty()) {
+                                dtsCorrection = 0;
+                            } else {
+                                var _lastSample2 = this._videoSegmentInfoList.getLastSampleBefore(firstSampleOriginalDts);
+                                if (_lastSample2 != null) {
+                                    var distance = firstSampleOriginalDts - (_lastSample2.originalDts + _lastSample2.duration);
+                                    if (distance <= 3) {
+                                        distance = 0;
+                                    }
+                                    var expectedDts = _lastSample2.dts + _lastSample2.duration + distance;
+                                    dtsCorrection = firstSampleOriginalDts - expectedDts;
+                                } else {
+                                    // lastSample == null, cannot found
+                                    dtsCorrection = 0;
+                                }
+                            }
+                        }
+
+                        var info = new _mediaSegmentInfo.MediaSegmentInfo();
+                        var mp4Samples = [];
+
+                        // Correct dts for each sample, and calculate sample duration. Then output to mp4Samples
+                        for (var i = 0; i < samples.length; i++) {
+                            var _sample2 = samples[i];
+                            var originalDts = _sample2.dts - this._dtsBase;
+                            var isKeyframe = _sample2.isKeyframe;
+                            var dts = originalDts - dtsCorrection;
+                            var cts = _sample2.cts;
+                            var pts = dts + cts;
+
+                            if (firstDts === -1) {
+                                firstDts = dts;
+                                firstPts = pts;
+                            }
+
+                            var sampleDuration = 0;
+
+                            if (i !== samples.length - 1) {
+                                var nextDts = samples[i + 1].dts - this._dtsBase - dtsCorrection;
+                                sampleDuration = nextDts - dts;
+                            } else {
+                                // the last sample
+                                if (lastSample != null) {
+                                    // use stashed sample's dts to calculate sample duration
+                                    var _nextDts2 = lastSample.dts - this._dtsBase - dtsCorrection;
+                                    sampleDuration = _nextDts2 - dts;
+                                } else if (mp4Samples.length >= 1) {
+                                    // use second last sample duration
+                                    sampleDuration = mp4Samples[mp4Samples.length - 1].duration;
+                                } else {
+                                    // the only one sample, use reference sample duration
+                                    sampleDuration = Math.floor(this._videoMeta.refSampleDuration);
+                                }
+                            }
+
+                            if (isKeyframe) {
+                                var syncPoint = new _mediaSegmentInfo.SampleInfo(dts, pts, sampleDuration, _sample2.dts, true);
+                                syncPoint.fileposition = _sample2.fileposition;
+                                info.appendSyncPoint(syncPoint);
+                            }
+
+                            mp4Samples.push({
+                                dts: dts,
+                                pts: pts,
+                                cts: cts,
+                                units: _sample2.units,
+                                size: _sample2.length,
+                                isKeyframe: isKeyframe,
+                                duration: sampleDuration,
+                                originalDts: originalDts,
+                                flags: {
+                                    isLeading: 0,
+                                    dependsOn: isKeyframe ? 2 : 1,
+                                    isDependedOn: isKeyframe ? 1 : 0,
+                                    hasRedundancy: 0,
+                                    isNonSync: isKeyframe ? 0 : 1
+                                }
+                            });
+                        }
+
+                        // allocate mdatbox
+                        mdatbox = new Uint8Array(mdatBytes);
+                        mdatbox[0] = mdatBytes >>> 24 & 0xFF;
+                        mdatbox[1] = mdatBytes >>> 16 & 0xFF;
+                        mdatbox[2] = mdatBytes >>> 8 & 0xFF;
+                        mdatbox[3] = mdatBytes & 0xFF;
+                        mdatbox.set(_mp4Generator2.default.types.mdat, 4);
+
+                        // Write samples into mdatbox
+                        for (var _i2 = 0; _i2 < mp4Samples.length; _i2++) {
+                            var units = mp4Samples[_i2].units;
+                            while (units.length) {
+                                var unit = units.shift();
+                                var data = unit.data;
+                                mdatbox.set(data, offset);
+                                offset += data.byteLength;
+                            }
+                        }
+
+                        var latest = mp4Samples[mp4Samples.length - 1];
+                        lastDts = latest.dts + latest.duration;
+                        lastPts = latest.pts + latest.duration;
+                        this._videoNextDts = lastDts;
+
+                        // fill media segment info & add to info list
+                        info.beginDts = firstDts;
+                        info.endDts = lastDts;
+                        info.beginPts = firstPts;
+                        info.endPts = lastPts;
+                        info.originalBeginDts = mp4Samples[0].originalDts;
+                        info.originalEndDts = latest.originalDts + latest.duration;
+                        info.firstSample = new _mediaSegmentInfo.SampleInfo(mp4Samples[0].dts, mp4Samples[0].pts, mp4Samples[0].duration, mp4Samples[0].originalDts, mp4Samples[0].isKeyframe);
+                        info.lastSample = new _mediaSegmentInfo.SampleInfo(latest.dts, latest.pts, latest.duration, latest.originalDts, latest.isKeyframe);
+                        if (!this._isLive) {
+                            this._videoSegmentInfoList.append(info);
+                        }
+
+                        track.samples = mp4Samples;
+                        track.sequenceNumber++;
+
+                        // workaround for chrome < 50: force first sample as a random access point
+                        // see https://bugs.chromium.org/p/chromium/issues/detail?id=229412
+                        if (this._forceFirstIDR) {
+                            var flags = mp4Samples[0].flags;
+                            flags.dependsOn = 2;
+                            flags.isNonSync = 0;
+                        }
+
+                        var moofbox = _mp4Generator2.default.moof(track, firstDts);
+                        track.samples = [];
+                        track.length = 0;
+
+                        this._onMediaSegment('video', {
+                            type: 'video',
+                            data: this._mergeBoxes(moofbox, mdatbox).buffer,
+                            sampleCount: mp4Samples.length,
+                            info: info
+                        });
+                    }
+                }, {
+                    key: '_mergeBoxes',
+                    value: function _mergeBoxes(moof, mdat) {
+                        var result = new Uint8Array(moof.byteLength + mdat.byteLength);
+                        result.set(moof, 0);
+                        result.set(mdat, moof.byteLength);
+                        return result;
+                    }
+                }, {
+                    key: 'onInitSegment',
+                    get: function get() {
+                        return this._onInitSegment;
+                    },
+                    set: function set(callback) {
+                        this._onInitSegment = callback;
+                    }
+
+                    /* prototype: function onMediaSegment(type: string, mediaSegment: MediaSegment): void
+                       MediaSegment: {
+                           type: string,
+                           data: ArrayBuffer,
+                           sampleCount: int32
+                           info: MediaSegmentInfo
+                       }
+                    */
+
+                }, {
+                    key: 'onMediaSegment',
+                    get: function get() {
+                        return this._onMediaSegment;
+                    },
+                    set: function set(callback) {
+                        this._onMediaSegment = callback;
+                    }
+                }]);
+
+                return MP4Remuxer;
+            }();
+
+            exports.default = MP4Remuxer;
+
+        }, { "../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) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var Browser = {};
+
+            function detect() {
+                // modified from jquery-browser-plugin
+
+                var ua = self.navigator.userAgent.toLowerCase();
+
+                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) || [];
+
+                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) || [];
+
+                var matched = {
+                    browser: match[5] || match[3] || match[1] || '',
+                    version: match[2] || match[4] || '0',
+                    majorVersion: match[4] || match[2] || '0',
+                    platform: platform_match[0] || ''
+                };
+
+                var browser = {};
+                if (matched.browser) {
+                    browser[matched.browser] = true;
+
+                    var versionArray = matched.majorVersion.split('.');
+                    browser.version = {
+                        major: parseInt(matched.majorVersion, 10),
+                        string: matched.version
+                    };
+                    if (versionArray.length > 1) {
+                        browser.version.minor = parseInt(versionArray[1], 10);
+                    }
+                    if (versionArray.length > 2) {
+                        browser.version.build = parseInt(versionArray[2], 10);
+                    }
+                }
+
+                if (matched.platform) {
+                    browser[matched.platform] = true;
+                }
+
+                if (browser.chrome || browser.opr || browser.safari) {
+                    browser.webkit = true;
+                }
+
+                // MSIE. IE11 has 'rv' identifer
+                if (browser.rv || browser.iemobile) {
+                    if (browser.rv) {
+                        delete browser.rv;
+                    }
+                    var msie = 'msie';
+                    matched.browser = msie;
+                    browser[msie] = true;
+                }
+
+                // Microsoft Edge
+                if (browser.edge) {
+                    delete browser.edge;
+                    var msedge = 'msedge';
+                    matched.browser = msedge;
+                    browser[msedge] = true;
+                }
+
+                // Opera 15+
+                if (browser.opr) {
+                    var opera = 'opera';
+                    matched.browser = opera;
+                    browser[opera] = true;
+                }
+
+                // Stock android browsers are marked as Safari
+                if (browser.safari && browser.android) {
+                    var android = 'android';
+                    matched.browser = android;
+                    browser[android] = true;
+                }
+
+                browser.name = matched.browser;
+                browser.platform = matched.platform;
+
+                for (var key in Browser) {
+                    if (Browser.hasOwnProperty(key)) {
+                        delete Browser[key];
+                    }
+                }
+                Object.assign(Browser, browser);
             }
-        }
-    }]);
 
-    return Polyfill;
-}();
+            detect();
 
-Polyfill.install();
+            exports.default = Browser;
 
-exports.default = Polyfill;
+        }, {}], 40: [function (_dereq_, module, exports) {
+            'use strict';
 
-},{"es6-promise":1}],44:[function(_dereq_,module,exports){
-'use strict';
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
 
-Object.defineProperty(exports, "__esModule", {
-    value: true
-});
-/*
- * Copyright (C) 2016 Bilibili. All Rights Reserved.
- *
- * This file is derived from C++ project libWinTF8 (https://github.com/m13253/libWinTF8)
- * @author zheng qian <xqq@xqq.im>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+            var _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; }; }();
 
-function checkContinuation(uint8array, start, checkLength) {
-    var array = uint8array;
-    if (start + checkLength < array.length) {
-        while (checkLength--) {
-            if ((array[++start] & 0xC0) !== 0x80) return false;
-        }
-        return true;
-    } else {
-        return false;
-    }
-}
+            function _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; }
 
-function decodeUTF8(uint8array) {
-    var out = [];
-    var input = uint8array;
-    var i = 0;
-    var length = uint8array.length;
+            function _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; }
 
-    while (i < length) {
-        if (input[i] < 0x80) {
-            out.push(String.fromCharCode(input[i]));
-            ++i;
-            continue;
-        } else if (input[i] < 0xC0) {
-            // fallthrough
-        } else if (input[i] < 0xE0) {
-            if (checkContinuation(input, i, 1)) {
-                var ucs4 = (input[i] & 0x1F) << 6 | input[i + 1] & 0x3F;
-                if (ucs4 >= 0x80) {
-                    out.push(String.fromCharCode(ucs4 & 0xFFFF));
-                    i += 2;
-                    continue;
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var RuntimeException = exports.RuntimeException = function () {
+                function RuntimeException(message) {
+                    _classCallCheck(this, RuntimeException);
+
+                    this._message = message;
+                }
+
+                _createClass(RuntimeException, [{
+                    key: 'toString',
+                    value: function toString() {
+                        return this.name + ': ' + this.message;
+                    }
+                }, {
+                    key: 'name',
+                    get: function get() {
+                        return 'RuntimeException';
+                    }
+                }, {
+                    key: 'message',
+                    get: function get() {
+                        return this._message;
+                    }
+                }]);
+
+                return RuntimeException;
+            }();
+
+            var IllegalStateException = exports.IllegalStateException = function (_RuntimeException) {
+                _inherits(IllegalStateException, _RuntimeException);
+
+                function IllegalStateException(message) {
+                    _classCallCheck(this, IllegalStateException);
+
+                    return _possibleConstructorReturn(this, (IllegalStateException.__proto__ || Object.getPrototypeOf(IllegalStateException)).call(this, message));
+                }
+
+                _createClass(IllegalStateException, [{
+                    key: 'name',
+                    get: function get() {
+                        return 'IllegalStateException';
+                    }
+                }]);
+
+                return IllegalStateException;
+            }(RuntimeException);
+
+            var InvalidArgumentException = exports.InvalidArgumentException = function (_RuntimeException2) {
+                _inherits(InvalidArgumentException, _RuntimeException2);
+
+                function InvalidArgumentException(message) {
+                    _classCallCheck(this, InvalidArgumentException);
+
+                    return _possibleConstructorReturn(this, (InvalidArgumentException.__proto__ || Object.getPrototypeOf(InvalidArgumentException)).call(this, message));
+                }
+
+                _createClass(InvalidArgumentException, [{
+                    key: 'name',
+                    get: function get() {
+                        return 'InvalidArgumentException';
+                    }
+                }]);
+
+                return InvalidArgumentException;
+            }(RuntimeException);
+
+            var NotImplementedException = exports.NotImplementedException = function (_RuntimeException3) {
+                _inherits(NotImplementedException, _RuntimeException3);
+
+                function NotImplementedException(message) {
+                    _classCallCheck(this, NotImplementedException);
+
+                    return _possibleConstructorReturn(this, (NotImplementedException.__proto__ || Object.getPrototypeOf(NotImplementedException)).call(this, message));
+                }
+
+                _createClass(NotImplementedException, [{
+                    key: 'name',
+                    get: function get() {
+                        return 'NotImplementedException';
+                    }
+                }]);
+
+                return NotImplementedException;
+            }(RuntimeException);
+
+        }, {}], 41: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }(); /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
+
+            var _events = _dereq_('events');
+
+            var _events2 = _interopRequireDefault(_events);
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            var Log = function () {
+                function Log() {
+                    _classCallCheck(this, Log);
+                }
+
+                _createClass(Log, null, [{
+                    key: 'e',
+                    value: function e(tag, msg) {
+                        if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
+
+                        var str = '[' + tag + '] > ' + msg;
+
+                        if (Log.ENABLE_CALLBACK) {
+                            Log.emitter.emit('log', 'error', str);
+                        }
+
+                        if (!Log.ENABLE_ERROR) {
+                            return;
+                        }
+
+                        //手动添加try
+                        try {
+
+                            if (console.error) {
+                                // console.error(str);//报错
+                            } else if (console.warn) {
+                                console.warn(str);
+                            } else {
+                                console.log(str);
+                            }
+                        }
+                        catch (err) {
+                            console.log('1259报错')
+                        }
+
+                    }
+                }, {
+                    key: 'i',
+                    value: function i(tag, msg) {
+                        if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
+
+                        var str = '[' + tag + '] > ' + msg;
+
+                        if (Log.ENABLE_CALLBACK) {
+                            Log.emitter.emit('log', 'info', str);
+                        }
+
+                        if (!Log.ENABLE_INFO) {
+                            return;
+                        }
+
+                        if (console.info) {
+                            console.info(str);
+                        } else {
+                            console.log(str);
+                        }
+                    }
+                }, {
+                    key: 'w',
+                    value: function w(tag, msg) {
+                        if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
+
+                        var str = '[' + tag + '] > ' + msg;
+
+                        if (Log.ENABLE_CALLBACK) {
+                            Log.emitter.emit('log', 'warn', str);
+                        }
+
+                        if (!Log.ENABLE_WARN) {
+                            return;
+                        }
+
+                        if (console.warn) {
+                            console.warn(str);
+                        } else {
+                            console.log(str);
+                        }
+                    }
+                }, {
+                    key: 'd',
+                    value: function d(tag, msg) {
+                        if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
+
+                        var str = '[' + tag + '] > ' + msg;
+
+                        if (Log.ENABLE_CALLBACK) {
+                            Log.emitter.emit('log', 'debug', str);
+                        }
+
+                        if (!Log.ENABLE_DEBUG) {
+                            return;
+                        }
+
+                        if (console.debug) {
+                            console.debug(str);
+                        } else {
+                            console.log(str);
+                        }
+                    }
+                }, {
+                    key: 'v',
+                    value: function v(tag, msg) {
+                        if (!tag || Log.FORCE_GLOBAL_TAG) tag = Log.GLOBAL_TAG;
+
+                        var str = '[' + tag + '] > ' + msg;
+
+                        if (Log.ENABLE_CALLBACK) {
+                            Log.emitter.emit('log', 'verbose', str);
+                        }
+
+                        if (!Log.ENABLE_VERBOSE) {
+                            return;
+                        }
+
+                        // console.log(str);
+                    }
+                }]);
+
+                return Log;
+            }();
+
+            Log.GLOBAL_TAG = 'flv.js';
+            Log.FORCE_GLOBAL_TAG = false;
+            Log.ENABLE_ERROR = true;
+            Log.ENABLE_INFO = true;
+            Log.ENABLE_WARN = true;
+            Log.ENABLE_DEBUG = true;
+            Log.ENABLE_VERBOSE = true;
+
+            Log.ENABLE_CALLBACK = false;
+
+            Log.emitter = new _events2.default();
+
+            exports.default = Log;
+
+        }, { "events": 2 }], 42: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }(); /*
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (C) 2016 Bilibili. All Rights Reserved.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * @author zheng qian <xqq@xqq.im>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Licensed under the Apache License, Version 2.0 (the "License");
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * you may not use this file except in compliance with the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * You may obtain a copy of the License at
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *     http://www.apache.org/licenses/LICENSE-2.0
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      *
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Unless required by applicable law or agreed to in writing, software
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * distributed under the License is distributed on an "AS IS" BASIS,
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * See the License for the specific language governing permissions and
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * limitations under the License.
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */
+
+            var _events = _dereq_('events');
+
+            var _events2 = _interopRequireDefault(_events);
+
+            var _logger = _dereq_('./logger.js');
+
+            var _logger2 = _interopRequireDefault(_logger);
+
+            function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            var LoggingControl = function () {
+                function LoggingControl() {
+                    _classCallCheck(this, LoggingControl);
+                }
+
+                _createClass(LoggingControl, null, [{
+                    key: 'getConfig',
+                    value: function getConfig() {
+                        return {
+                            globalTag: _logger2.default.GLOBAL_TAG,
+                            forceGlobalTag: _logger2.default.FORCE_GLOBAL_TAG,
+                            enableVerbose: _logger2.default.ENABLE_VERBOSE,
+                            enableDebug: _logger2.default.ENABLE_DEBUG,
+                            enableInfo: _logger2.default.ENABLE_INFO,
+                            enableWarn: _logger2.default.ENABLE_WARN,
+                            enableError: _logger2.default.ENABLE_ERROR,
+                            enableCallback: _logger2.default.ENABLE_CALLBACK
+                        };
+                    }
+                }, {
+                    key: 'applyConfig',
+                    value: function applyConfig(config) {
+                        _logger2.default.GLOBAL_TAG = config.globalTag;
+                        _logger2.default.FORCE_GLOBAL_TAG = config.forceGlobalTag;
+                        _logger2.default.ENABLE_VERBOSE = config.enableVerbose;
+                        _logger2.default.ENABLE_DEBUG = config.enableDebug;
+                        _logger2.default.ENABLE_INFO = config.enableInfo;
+                        _logger2.default.ENABLE_WARN = config.enableWarn;
+                        _logger2.default.ENABLE_ERROR = config.enableError;
+                        _logger2.default.ENABLE_CALLBACK = config.enableCallback;
+                    }
+                }, {
+                    key: '_notifyChange',
+                    value: function _notifyChange() {
+                        var emitter = LoggingControl.emitter;
+
+                        if (emitter.listenerCount('change') > 0) {
+                            var config = LoggingControl.getConfig();
+                            emitter.emit('change', config);
+                        }
+                    }
+                }, {
+                    key: 'registerListener',
+                    value: function registerListener(listener) {
+                        LoggingControl.emitter.addListener('change', listener);
+                    }
+                }, {
+                    key: 'removeListener',
+                    value: function removeListener(listener) {
+                        LoggingControl.emitter.removeListener('change', listener);
+                    }
+                }, {
+                    key: 'addLogListener',
+                    value: function addLogListener(listener) {
+                        _logger2.default.emitter.addListener('log', listener);
+                        if (_logger2.default.emitter.listenerCount('log') > 0) {
+                            _logger2.default.ENABLE_CALLBACK = true;
+                            LoggingControl._notifyChange();
+                        }
+                    }
+                }, {
+                    key: 'removeLogListener',
+                    value: function removeLogListener(listener) {
+                        _logger2.default.emitter.removeListener('log', listener);
+                        if (_logger2.default.emitter.listenerCount('log') === 0) {
+                            _logger2.default.ENABLE_CALLBACK = false;
+                            LoggingControl._notifyChange();
+                        }
+                    }
+                }, {
+                    key: 'forceGlobalTag',
+                    get: function get() {
+                        return _logger2.default.FORCE_GLOBAL_TAG;
+                    },
+                    set: function set(enable) {
+                        _logger2.default.FORCE_GLOBAL_TAG = enable;
+                        LoggingControl._notifyChange();
+                    }
+                }, {
+                    key: 'globalTag',
+                    get: function get() {
+                        return _logger2.default.GLOBAL_TAG;
+                    },
+                    set: function set(tag) {
+                        _logger2.default.GLOBAL_TAG = tag;
+                        LoggingControl._notifyChange();
+                    }
+                }, {
+                    key: 'enableAll',
+                    get: function get() {
+                        return _logger2.default.ENABLE_VERBOSE && _logger2.default.ENABLE_DEBUG && _logger2.default.ENABLE_INFO && _logger2.default.ENABLE_WARN && _logger2.default.ENABLE_ERROR;
+                    },
+                    set: function set(enable) {
+                        _logger2.default.ENABLE_VERBOSE = enable;
+                        _logger2.default.ENABLE_DEBUG = enable;
+                        _logger2.default.ENABLE_INFO = enable;
+                        _logger2.default.ENABLE_WARN = enable;
+                        _logger2.default.ENABLE_ERROR = enable;
+                        LoggingControl._notifyChange();
+                    }
+                }, {
+                    key: 'enableDebug',
+                    get: function get() {
+                        return _logger2.default.ENABLE_DEBUG;
+                    },
+                    set: function set(enable) {
+                        _logger2.default.ENABLE_DEBUG = enable;
+                        LoggingControl._notifyChange();
+                    }
+                }, {
+                    key: 'enableVerbose',
+                    get: function get() {
+                        return _logger2.default.ENABLE_VERBOSE;
+                    },
+                    set: function set(enable) {
+                        _logger2.default.ENABLE_VERBOSE = enable;
+                        LoggingControl._notifyChange();
+                    }
+                }, {
+                    key: 'enableInfo',
+                    get: function get() {
+                        return _logger2.default.ENABLE_INFO;
+                    },
+                    set: function set(enable) {
+                        _logger2.default.ENABLE_INFO = enable;
+                        LoggingControl._notifyChange();
+                    }
+                }, {
+                    key: 'enableWarn',
+                    get: function get() {
+                        return _logger2.default.ENABLE_WARN;
+                    },
+                    set: function set(enable) {
+                        _logger2.default.ENABLE_WARN = enable;
+                        LoggingControl._notifyChange();
+                    }
+                }, {
+                    key: 'enableError',
+                    get: function get() {
+                        return _logger2.default.ENABLE_ERROR;
+                    },
+                    set: function set(enable) {
+                        _logger2.default.ENABLE_ERROR = enable;
+                        LoggingControl._notifyChange();
+                    }
+                }]);
+
+                return LoggingControl;
+            }();
+
+            LoggingControl.emitter = new _events2.default();
+
+            exports.default = LoggingControl;
+
+        }, { "./logger.js": 41, "events": 2 }], 43: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+
+            var _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; }; }();
+
+            function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            var Polyfill = function () {
+                function Polyfill() {
+                    _classCallCheck(this, Polyfill);
+                }
+
+                _createClass(Polyfill, null, [{
+                    key: 'install',
+                    value: function install() {
+                        // ES6 Object.setPrototypeOf
+                        Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
+                            obj.__proto__ = proto;
+                            return obj;
+                        };
+
+                        // ES6 Object.assign
+                        Object.assign = Object.assign || function (target) {
+                            if (target === undefined || target === null) {
+                                throw new TypeError('Cannot convert undefined or null to object');
+                            }
+
+                            var output = Object(target);
+                            for (var i = 1; i < arguments.length; i++) {
+                                var source = arguments[i];
+                                if (source !== undefined && source !== null) {
+                                    for (var key in source) {
+                                        if (source.hasOwnProperty(key)) {
+                                            output[key] = source[key];
+                                        }
+                                    }
+                                }
+                            }
+                            return output;
+                        };
+
+                        // ES6 Promise (missing support in IE11)
+                        if (typeof self.Promise !== 'function') {
+                            _dereq_('es6-promise').polyfill();
+                        }
+                    }
+                }]);
+
+                return Polyfill;
+            }();
+
+            Polyfill.install();
+
+            exports.default = Polyfill;
+
+        }, { "es6-promise": 1 }], 44: [function (_dereq_, module, exports) {
+            'use strict';
+
+            Object.defineProperty(exports, "__esModule", {
+                value: true
+            });
+            /*
+             * Copyright (C) 2016 Bilibili. All Rights Reserved.
+             *
+             * This file is derived from C++ project libWinTF8 (https://github.com/m13253/libWinTF8)
+             * @author zheng qian <xqq@xqq.im>
+             *
+             * Licensed under the Apache License, Version 2.0 (the "License");
+             * you may not use this file except in compliance with the License.
+             * You may obtain a copy of the License at
+             *
+             *     http://www.apache.org/licenses/LICENSE-2.0
+             *
+             * Unless required by applicable law or agreed to in writing, software
+             * distributed under the License is distributed on an "AS IS" BASIS,
+             * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+             * See the License for the specific language governing permissions and
+             * limitations under the License.
+             */
+
+            function checkContinuation(uint8array, start, checkLength) {
+                var array = uint8array;
+                if (start + checkLength < array.length) {
+                    while (checkLength--) {
+                        if ((array[++start] & 0xC0) !== 0x80) return false;
+                    }
+                    return true;
+                } else {
+                    return false;
                 }
             }
-        } else if (input[i] < 0xF0) {
-            if (checkContinuation(input, i, 2)) {
-                var _ucs = (input[i] & 0xF) << 12 | (input[i + 1] & 0x3F) << 6 | input[i + 2] & 0x3F;
-                if (_ucs >= 0x800 && (_ucs & 0xF800) !== 0xD800) {
-                    out.push(String.fromCharCode(_ucs & 0xFFFF));
-                    i += 3;
-                    continue;
+
+            function decodeUTF8(uint8array) {
+                var out = [];
+                var input = uint8array;
+                var i = 0;
+                var length = uint8array.length;
+
+                while (i < length) {
+                    if (input[i] < 0x80) {
+                        out.push(String.fromCharCode(input[i]));
+                        ++i;
+                        continue;
+                    } else if (input[i] < 0xC0) {
+                        // fallthrough
+                    } else if (input[i] < 0xE0) {
+                        if (checkContinuation(input, i, 1)) {
+                            var ucs4 = (input[i] & 0x1F) << 6 | input[i + 1] & 0x3F;
+                            if (ucs4 >= 0x80) {
+                                out.push(String.fromCharCode(ucs4 & 0xFFFF));
+                                i += 2;
+                                continue;
+                            }
+                        }
+                    } else if (input[i] < 0xF0) {
+                        if (checkContinuation(input, i, 2)) {
+                            var _ucs = (input[i] & 0xF) << 12 | (input[i + 1] & 0x3F) << 6 | input[i + 2] & 0x3F;
+                            if (_ucs >= 0x800 && (_ucs & 0xF800) !== 0xD800) {
+                                out.push(String.fromCharCode(_ucs & 0xFFFF));
+                                i += 3;
+                                continue;
+                            }
+                        }
+                    } else if (input[i] < 0xF8) {
+                        if (checkContinuation(input, i, 3)) {
+                            var _ucs2 = (input[i] & 0x7) << 18 | (input[i + 1] & 0x3F) << 12 | (input[i + 2] & 0x3F) << 6 | input[i + 3] & 0x3F;
+                            if (_ucs2 > 0x10000 && _ucs2 < 0x110000) {
+                                _ucs2 -= 0x10000;
+                                out.push(String.fromCharCode(_ucs2 >>> 10 | 0xD800));
+                                out.push(String.fromCharCode(_ucs2 & 0x3FF | 0xDC00));
+                                i += 4;
+                                continue;
+                            }
+                        }
+                    }
+                    out.push(String.fromCharCode(0xFFFD));
+                    ++i;
                 }
+
+                return out.join('');
             }
-        } else if (input[i] < 0xF8) {
-            if (checkContinuation(input, i, 3)) {
-                var _ucs2 = (input[i] & 0x7) << 18 | (input[i + 1] & 0x3F) << 12 | (input[i + 2] & 0x3F) << 6 | input[i + 3] & 0x3F;
-                if (_ucs2 > 0x10000 && _ucs2 < 0x110000) {
-                    _ucs2 -= 0x10000;
-                    out.push(String.fromCharCode(_ucs2 >>> 10 | 0xD800));
-                    out.push(String.fromCharCode(_ucs2 & 0x3FF | 0xDC00));
-                    i += 4;
-                    continue;
-                }
-            }
-        }
-        out.push(String.fromCharCode(0xFFFD));
-        ++i;
-    }
 
-    return out.join('');
-}
+            exports.default = decodeUTF8;
 
-exports.default = decodeUTF8;
-
-},{}]},{},[21])(21)
+        }, {}]
+    }, {}, [21])(21)
 });
 
 //# sourceMappingURL=flv.js.map

--
Gitblit v1.9.3