PageSourceSearch

https://geotez.tv/assets/front/js/videojs/js/videojs-contrib-hls.js

js geotez.tv collected 2026-09-25 09:09:20 UTC 519,541 bytes, 16,056 lines download raw bytes

1/**
2 * videojs-contrib-hls
3 * @version 3.6.7
4 * @copyright 2016 Brightcove, Inc
5 * @license Apache-2.0
6 */
7(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.videojsContribHls = 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(require,module,exports){
8/**
9 * @file ad-cue-tags.js
10 */
11'use strict';
12
13Object.defineProperty(exports, '__esModule', {
14  value: true
15});
16
17var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
18
19function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
20
21var _globalWindow = require('global/window');
22
23var _globalWindow2 = _interopRequireDefault(_globalWindow);
24
25/**
26 * Searches for an ad cue that overlaps with the given mediaTime
27 */
28var findAdCue = function findAdCue(track, mediaTime) {
29  var cues = track.cues;
30
31  for (var i = 0; i < cues.length; i++) {
32    var cue = cues[i];
33
34    if (mediaTime >= cue.adStartTime && mediaTime <= cue.adEndTime) {
35      return cue;
36    }
37  }
38  return null;
39};
40
41var updateAdCues = function updateAdCues(media, track) {
42  var offset = arguments.length <= 2 || arguments[2] === undefined ? 0 : arguments[2];
43
44  if (!media.segments) {
45    return;
46  }
47
48  var mediaTime = offset;
49  var cue = undefined;
50
51  for (var i = 0; i < media.segments.length; i++) {
52    var segment = media.segments[i];
53
54    if (!cue) {
55      // Since the cues will span for at least the segment duration, adding a fudge
56      // factor of half segment duration will prevent duplicate cues from being
57      // created when timing info is not exact (e.g. cue start time initialized
58      // at 10.006677, but next call mediaTime is 10.003332 )
59      cue = findAdCue(track, mediaTime + segment.duration / 2);
60    }
61
62    if (cue) {
63      if ('cueIn' in segment) {
64        // Found a CUE-IN so end the cue
65        cue.endTime = mediaTime;
66        cue.adEndTime = mediaTime;
67        mediaTime += segment.duration;
68        cue = null;
69        continue;
70      }
71
72      if (mediaTime < cue.endTime) {
73        // Already processed this mediaTime for this cue
74        mediaTime += segment.duration;
75        continue;
76      }
77
78      // otherwise extend cue until a CUE-IN is found
79      cue.endTime += segment.duration;
80    } else {
81      if ('cueOut' in segment) {
82        cue = new _globalWindow2['default'].VTTCue(mediaTime, mediaTime + segment.duration, segment.cueOut);
83        cue.adStartTime = mediaTime;
84        // Assumes tag format to be
85        // #EXT-X-CUE-OUT:30
86        cue.adEndTime = mediaTime + parseFloat(segment.cueOut);
87        track.addCue(cue);
88      }
89
90      if ('cueOutCont' in segment) {
91        // Entered into the middle of an ad cue
92        var adOffset = undefined;
93        var adTotal = undefined;
94
95        // Assumes tag formate to be
96        // #EXT-X-CUE-OUT-CONT:10/30
97
98        var _segment$cueOutCont$split$map = segment.cueOutCont.split('/').map(parseFloat);
99
100        var _segment$cueOutCont$split$map2 = _slicedToArray(_segment$cueOutCont$split$map, 2);
101
102        adOffset = _segment$cueOutCont$split$map2[0];
103        adTotal = _segment$cueOutCont$split$map2[1];
104
105        cue = new _globalWindow2['default'].VTTCue(mediaTime, mediaTime + segment.duration, '');
106        cue.adStartTime = mediaTime - adOffset;
107        cue.adEndTime = cue.adStartTime + adTotal;
108        track.addCue(cue);
109      }
110    }
111    mediaTime += segment.duration;
112  }
113};
114
115exports['default'] = {
116  updateAdCues: updateAdCues,
117  findAdCue: findAdCue
118};
119module.exports = exports['default'];
120},{"global/window":25}],2:[function(require,module,exports){
121/**
122 * @file bin-utils.js
123 */
124
125/**
126 * convert a TimeRange to text
127 *
128 * @param {TimeRange} range the timerange to use for conversion
129 * @param {Number} i the iterator on the range to convert
130 */
131'use strict';
132
133Object.defineProperty(exports, '__esModule', {
134  value: true
135});
136var textRange = function textRange(range, i) {
137  return range.start(i) + '-' + range.end(i);
138};
139
140/**
141 * format a number as hex string
142 *
143 * @param {Number} e The number
144 * @param {Number} i the iterator
145 */
146var formatHexString = function formatHexString(e, i) {
147  var value = e.toString(16);
148
149  return '00'.substring(0, 2 - value.length) + value + (i % 2 ? ' ' : '');
150};
151var formatAsciiString = function formatAsciiString(e) {
152  if (e >= 0x20 && e < 0x7e) {
153    return String.fromCharCode(e);
154  }
155  return '.';
156};
157
158/**
159 * utils to help dump binary data to the console
160 */
161var utils = {
162  hexDump: function hexDump(data) {
163    var bytes = Array.prototype.slice.call(data);
164    var step = 16;
165    var result = '';
166    var hex = undefined;
167    var ascii = undefined;
168
169    for (var j = 0;
169 j < bytes.length / step; j++) {
170      hex = bytes.slice(j * step, j * step + step).map(formatHexString).join('');
171      ascii = bytes.slice(j * step, j * step + step).map(formatAsciiString).join('');
172      result += hex + ' ' + ascii + '\n';
173    }
174    return result;
175  },
176  tagDump: function tagDump(tag) {
177    return utils.hexDump(tag.bytes);
178  },
179  textRanges: function textRanges(ranges) {
180    var result = '';
181    var i = undefined;
182
183    for (i = 0; i < ranges.length; i++) {
184      result += textRange(ranges, i) + ' ';
185    }
186    return result;
187  }
188};
189
190exports['default'] = utils;
191module.exports = exports['default'];
192},{}],3:[function(require,module,exports){
193"use strict";
194
195Object.defineProperty(exports, "__esModule", {
196  value: true
197});
198exports["default"] = {
199  GOAL_BUFFER_LENGTH: 30
200};
201module.exports = exports["default"];
202},{}],4:[function(require,module,exports){
203(function (global){
204/**
205 * @file gap-skipper.js
206 */
207'use strict';
208
209Object.defineProperty(exports, '__esModule', {
210  value: true
211});
212
213var _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; }; })();
214
215function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
216
217function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
218
219var _ranges = require('./ranges');
220
221var _ranges2 = _interopRequireDefault(_ranges);
222
223var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
224
225var _videoJs2 = _interopRequireDefault(_videoJs);
226
227// Set of events that reset the gap-skipper logic and clear the timeout
228var timerCancelEvents = ['seeking', 'seeked', 'pause', 'playing', 'error'];
229
230/**
231 * The gap skipper object handles all scenarios
232 * where the player runs into the end of a buffered
233 * region and there is a buffered region ahead.
234 *
235 * It then handles the skipping behavior by setting a
236 * timer to the size (in time) of the gap. This gives
237 * the hls segment fetcher time to close the gap and
238 * resume playing before the timer is triggered and
239 * the gap skipper simply seeks over the gap as a
240 * last resort to resume playback.
241 *
242 * @class GapSkipper
243 */
244
245var GapSkipper = (function () {
246  /**
247   * Represents a GapSKipper object.
248   * @constructor
249   * @param {object} options an object that includes the tech and settings
250   */
251
252  function GapSkipper(options) {
253    var _this = this;
254
255    _classCallCheck(this, GapSkipper);
256
257    this.tech_ = options.tech;
258    this.consecutiveUpdates = 0;
259    this.lastRecordedTime = null;
260    this.timer_ = null;
261    this.checkCurrentTimeTimeout_ = null;
262
263    if (options.debug) {
264      this.logger_ = _videoJs2['default'].log.bind(_videoJs2['default'], 'gap-skipper ->');
265    }
266    this.logger_('initialize');
267
268    var waitingHandler = function waitingHandler() {
269      return _this.waiting_();
270    };
271    var cancelTimerHandler = function cancelTimerHandler() {
272      return _this.cancelTimer_();
273    };
274
275    this.tech_.on('waiting', waitingHandler);
276    this.tech_.on(timerCancelEvents, cancelTimerHandler);
277    this.monitorCurrentTime_();
278
279    // Define the dispose function to clean up our events
280    this.dispose = function () {
281      _this.logger_('dispose');
282      _this.tech_.off('waiting', waitingHandler);
283      _this.tech_.off(timerCancelEvents, cancelTimerHandler);
284      if (_this.checkCurrentTimeTimeout_) {
285        clearTimeout(_this.checkCurrentTimeTimeout_);
286      }
287      _this.cancelTimer_();
288    };
289  }
290
291  /**
292   * Periodically check for timeupdates to see if a gap has been encountered.
293   *
294   * @private
295   */
296
297  _createClass(GapSkipper, [{
298    key: 'monitorCurrentTime_',
299    value: function monitorCurrentTime_() {
300      this.checkCurrentTime_();
301
302      if (this.checkCurrentTimeTimeout_) {
303        clearTimeout(this.checkCurrentTimeTimeout_);
304      }
305
306      // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
307      this.checkCurrentTimeTimeout_ = setTimeout(this.monitorCurrentTime_.bind(this), 250);
308    }
309
310    /**
311     * Handler for `waiting` events from the player
312     *
313     * @private
314     */
315  }, {
316    key: 'waiting_',
317    value: function waiting_() {
318      if (!this.tech_.seeking()) {
319        this.setTimer_();
320      }
321    }
322
323    /**
324     * The purpose of this function is to emulate the "waiting" event on
325     * browsers that do not emit it when they are waiting for more
326     * data to continue playback
327     *
328     * @private
329     */
330  }, {
331    key: 'checkCurrentTime_',
332    value: function checkCurrentTime_() {
333      if (this.tech_.paused() || this.tech_.seeking()) {
334        return;
335      }
336
337      var currentTime = this.tech_.currentTime();
338
339      if (this.consecutiveUpdates === 5 && currentTime === this.lastRecordedTime) {
340        this.consecutiveUpdates++;
341        this.waiting_();
342      } else if (currentTime === this.lastRecordedTime) {
343        this.consecutiveUpdates++;
344      } else {
345        this.consecutiveUpdates = 0;
346        this.lastRecordedTime = currentTime;
347      }
348    }
349
350    /**
351     * Cancels any pending timers and resets the 'timeupdate' mechanism
352     * designed to detect that we are stalled
353     *
354     * @private
355     */
356  }, {
357    key: 'cancelTimer_',
358    value: function cancelTimer_() {
359      this.consecutiveUpdates = 0;
360
361      if (this.timer_) {
362        this.logger_('cancelTimer_');
363        clearTimeout(this.timer_);
364      }
365
366      this.timer_ = null;
367    }
368
369    /**
370     * Timer callback. If playback still has not proceeded, then we seek
371     * to the start of the next buffered region.
372     *
373     * @private
374     */
375  }, {
376    key: 'skipTheGap_',
377    value: function skipTheGap_(scheduledCurrentTime) {
378      var buffered = this.tech_.buffered();
379      var currentTime = this.tech_.currentTime();
380      var nextRange = _ranges2['default'].findNextRange(buffered, currentTime);
381
382      this.consecutiveUpdates = 0;
383      this.timer_ = null;
384
385      if (nextRange.length === 0 || currentTime !== scheduledCurrentTime) {
386        return;
387      }
388
389      this.logger_('skipTheGap_:', 'currentTime:', currentTime, 'scheduled currentTime:', scheduledCurrentTime, 'nextRange start:', nextRange.start(0));
390
391      // only seek if we still have not played
392      this.tech_.setCurrentTime(nextRange.start(0) + _ranges2['default'].TIME_FUDGE_FACTOR);
393    }
394  }, {
395    key: 'gapFromVideoUnderflow_',
396    value: function gapFromVideoUnderflow_(buffered, currentTime) {
397      // At least in Chrome, if there is a gap in the video buffer, the audio will continue
398      // playing for ~3 seconds after the video gap starts. This is done to account for
399      // video buffer underflow/underrun (note that this is not done when there is audio
400      // buffer underflow/underrun -- in that case the video will stop as soon as it
401      // encounters the gap, as audio stalls are more noticeable/jarring to a user than
402      // video stalls). The player's time will reflect the playthrough of audio, so the
403      // time will appear as if we are in a buffered region, even if we are stuck in a
404      // "gap."
405      //
406      // Example:
407      // video buffer:   0 => 10.1, 10.2 => 20
408      // audio buffer:   0 => 20
409      // overall buffer: 0 => 10.1, 10.2 => 20
410      // current time: 13
411      //
412      // Chrome's video froze at 10 seconds, where the video buffer encountered the gap,
413      // however, the audio continued playing until it reached ~3 seconds past the gap
414      // (13 seconds), at which point it stops as well. Since current time is past the
415      // gap, findNextRange will return no ranges.
416      //
417      // To check for this issue, we see if there is a gap that starts somewhere within
418      // a 3 second range (3 seconds +/- 1 second) back from our current time.
419      var gaps = _ranges2['default'].findGaps(buffered);
420
421      for (var i = 0; i < gaps.length; i++) {
422        var start = gaps.start(i);
423        var end = gaps.end(i);
424
425        // gap is starts no more than 4 seconds back
426        if (currentTime - start < 4 && currentTime - start > 2) {
427          return {
428            start: start,
429            end: end
430          };
431        }
432      }
433
434      return null;
435    }
436
437    /**
438     * Set a timer to skip the unbuffered region.
439     *
440     * @private
441     */
442  }, {
443    key: 'setTimer_',
444    value: function setTimer_() {
445      var buffered = this.tech_.buffered();
446      var currentTime = this.tech_.currentTime();
447      var nextRange = _ranges2['default'].findNextRange(buffered, currentTime);
448
449      if (this.timer_ !== null) {
450        return;
451      }
452
453      if (nextRange.length === 0) {
454        // Even if there is no available next range, there is still a possibility we are
455        // stuck in a gap due to video underflow.
456        var gap = this.gapFromVideoUnderflow_(buffered, currentTime);
457
458        if (gap) {
459          this.logger_('setTimer_:', 'Encountered a gap in video', 'from: ', gap.start, 'to: ', gap.end, 'seeking to current time: ', currentTime);
460          // Even though the video underflowed and was stuck in a gap, the audio overplayed
461          // the gap, leading currentTime into a buffered range. Seeking to currentTime
462          // allows the video to catch up to the audio position without losing any audio
463          // (only suffering ~3 seconds of frozen video and a pause in audio playback).
464          this.tech_.setCurrentTime(currentTime);
465        }
466        return;
467      }
468
469      var difference = nextRange.start(0) - currentTime;
470
471      this.logger_('setTimer_:', 'stopped at:', currentTime, 'setting timer for:', difference, 'seeking to:', nextRange.start(0));
472
473      this.timer_ = setTimeout(this.skipTheGap_.bind(this), difference * 1000, currentTime);
474    }
475
476    /**
477     * A debugging logger noop that is set to console.log only if debugging
478     * is enabled globally
479     *
480     * @private
481     */
482  }, {
483    key: 'logger_',
484    value: function logger_() {}
485  }]);
486
487  return GapSkipper;
488})();
489
490exports['default'] = GapSkipper;
491module.exports = exports['default'];
492}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
493},{"./ranges":8}],5:[function(require,module,exports){
494(function (global){
495/**
496 * @file master-playlist-controller.js
497 */
498'use strict';
499
500Object.defineProperty(exports, '__esModule', {
501  value: true
502});
503
504var _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; }; })();
505
506var _get = function get(_x3, _x4, _x5) { var _again = true; _function: while (_again) { var object = _x3, property = _x4, receiver = _x5; _again = false; 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 { _x3 = parent; _x4 = property; _x5 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
507
508function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
509
510function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
511
512function _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, { c
512onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
513
514var _playlistLoader = require('./playlist-loader');
515
516var _playlistLoader2 = _interopRequireDefault(_playlistLoader);
517
518var _segmentLoader = require('./segment-loader');
519
520var _segmentLoader2 = _interopRequireDefault(_segmentLoader);
521
522var _ranges = require('./ranges');
523
524var _ranges2 = _interopRequireDefault(_ranges);
525
526var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
527
528var _videoJs2 = _interopRequireDefault(_videoJs);
529
530var _adCueTags = require('./ad-cue-tags');
531
532var _adCueTags2 = _interopRequireDefault(_adCueTags);
533
534// 5 minute blacklist
535var BLACKLIST_DURATION = 5 * 60 * 1000;
536var Hls = undefined;
537
538/**
539 * determine if an object a is differnt from
540 * and object b. both only having one dimensional
541 * properties
542 *
543 * @param {Object} a object one
544 * @param {Object} b object two
545 * @return {Boolean} if the object has changed or not
546 */
547var objectChanged = function objectChanged(a, b) {
548  if (typeof a !== typeof b) {
549    return true;
550  }
551  // if we have a different number of elements
552  // something has changed
553  if (Object.keys(a).length !== Object.keys(b).length) {
554    return true;
555  }
556
557  for (var prop in a) {
558    if (a[prop] !== b[prop]) {
559      return true;
560    }
561  }
562  return false;
563};
564
565/**
566 * Parses a codec string to retrieve the number of codecs specified,
567 * the video codec and object type indicator, and the audio profile.
568 *
569 * @private
570 */
571var parseCodecs = function parseCodecs(codecs) {
572  var result = {
573    codecCount: 0,
574    videoCodec: null,
575    videoObjectTypeIndicator: null,
576    audioProfile: null
577  };
578  var parsed = undefined;
579
580  result.codecCount = codecs.split(',').length;
581  result.codecCount = result.codecCount || 2;
582
583  // parse the video codec
584  parsed = /(^|\s|,)+(avc1)([^ ,]*)/i.exec(codecs);
585  if (parsed) {
586    result.videoCodec = parsed[2];
587    result.videoObjectTypeIndicator = parsed[3];
588  }
589
590  // parse the last field of the audio codec
591  result.audioProfile = /(^|\s|,)+mp4a.[0-9A-Fa-f]+\.([0-9A-Fa-f]+)/i.exec(codecs);
592  result.audioProfile = result.audioProfile && result.audioProfile[2];
593
594  return result;
595};
596
597/**
598 * Calculates the MIME type strings for a working configuration of
599 * SourceBuffers to play variant streams in a master playlist. If
600 * there is no possible working configuration, an empty array will be
601 * returned.
602 *
603 * @param master {Object} the m3u8 object for the master playlist
604 * @param media {Object} the m3u8 object for the variant playlist
605 * @return {Array} the MIME type strings. If the array has more than
606 * one entry, the first element should be applied to the video
607 * SourceBuffer and the second to the audio SourceBuffer.
608 *
609 * @private
610 */
611var mimeTypesForPlaylist_ = function mimeTypesForPlaylist_(master, media) {
612  var container = 'mp2t';
613  var codecs = {
614    videoCodec: 'avc1',
615    videoObjectTypeIndicator: '.4d400d',
616    audioProfile: '2'
617  };
618  var audioGroup = [];
619  var mediaAttributes = undefined;
620  var previousGroup = null;
621
622  if (!media) {
623    // not enough information, return an error
624    return [];
625  }
626  // An initialization segment means the media playlists is an iframe
627  // playlist or is using the mp4 container. We don't currently
628  // support iframe playlists, so assume this is signalling mp4
629  // fragments.
630  // the existence check for segments can be removed once
631  // https://github.com/videojs/m3u8-parser/issues/8 is closed
632  if (media.segments && media.segments.length && media.segments[0].map) {
633    container = 'mp4';
634  }
635
636  // if the codecs were explicitly specified, use them instead of the
637  // defaults
638  mediaAttributes = media.attributes || {};
639  if (mediaAttributes.CODECS) {
640    (function () {
641      var parsedCodecs = parseCodecs(mediaAttributes.CODECS);
642
643      Object.keys(parsedCodecs).forEach(function (key) {
644        codecs[key] = parsedCodecs[key] || codecs[key];
645      });
646    })();
647  }
648
649  if (master.mediaGroups.AUDIO) {
650    audioGroup = master.mediaGroups.AUDIO[mediaAttributes.AUDIO];
651  }
652
653  // if audio could be muxed or unmuxed, use mime types appropriate
654  // for both scenarios
655  for (var groupId in audioGroup) {
656    if (previousGroup && !!audioGroup[groupId].uri !== !!previousGroup.uri) {
657      // one source buffer with muxed video and audio and another for
658      // the alternate audio
659      return ['video/' + container + '; codecs="' + codecs.videoCodec + codecs.videoObjectTypeIndicator + ', mp4a.40.' + codecs.audioProfile + '"', 'audio/' + container + '; codecs="mp4a.40.' + codecs.audioProfile + '"'];
660    }
661    previousGroup = audioGroup[groupId];
662  }
663  // if all video and audio is unmuxed, use two single-codec mime
664  // types
665  if (previousGroup && previousGroup.uri) {
666    return ['video/' + container + '; codecs="' + codecs.videoCodec + codecs.videoObjectTypeIndicator + '"', 'audio/' + container + '; codecs="mp4a.40.' + codecs.audioProfile + '"'];
667  }
668
669  // all video and audio are muxed, use a dual-codec mime type
670  return ['video/' + container + '; codecs="' + codecs.videoCodec + codecs.videoObjectTypeIndicator + ', mp4a.40.' + codecs.audioProfile + '"'];
671};
672
673exports.mimeTypesForPlaylist_ = mimeTypesForPlaylist_;
674/**
675 * the master playlist controller controller all interactons
676 * between playlists and segmentloaders. At this time this mainly
677 * involves a master playlist and a series of audio playlists
678 * if they are available
679 *
680 * @class MasterPlaylistController
681 * @extends videojs.EventTarget
682 */
683
684var MasterPlaylistController = (function (_videojs$EventTarget) {
685  _inherits(MasterPlaylistController, _videojs$EventTarget);
686
687  function MasterPlaylistController(options) {
688    var _this = this;
689
690    _classCallCheck(this, MasterPlaylistController);
691
692    _get(Object.getPrototypeOf(MasterPlaylistController.prototype), 'constructor', this).call(this);
693
694    var url = options.url;
695    var withCredentials = options.withCredentials;
696    var mode = options.mode;
697    var tech = options.tech;
698    var bandwidth = options.bandwidth;
699    var externHls = options.externHls;
700    var useCueTags = options.useCueTags;
701
702    if (!url) {
703      throw new Error('A non-empty playlist URL is required');
704    }
705
706    Hls = externHls;
707
708    this.withCredentials = withCredentials;
709    this.tech_ = tech;
710    this.hls_ = tech.hls;
711    this.mode_ = mode;
712    this.useCueTags_ = useCueTags;
713    if (this.useCueTags_) {
714      this.cueTagsTrack_ = this.tech_.addTextTrack('metadata', 'ad-cues');
715      this.cueTagsTrack_.inBandMetadataTrackDispatchType = '';
716      this.tech_.textTracks().addTrack_(this.cueTagsTrack_);
717    }
718
719    this.audioTracks_ = [];
720    this.requestOptions_ = {
721      withCredentials: this.withCredentials,
722      timeout: null
723    };
724
725    this.audioGroups_ = {};
726
727    this.mediaSource = new _videoJs2['default'].MediaSource({ mode: mode });
728    this.audioinfo_ = null;
729    this.mediaSource.on('audioinfo', this.handleAudioinfoUpdate_.bind(this));
730
731    // load the media source into the player
732    this.mediaSource.addEventListener('sourceopen', this.handleSourceOpen_.bind(this));
733
734    var segmentLoaderOptions = {
735      hls: this.hls_,
736      mediaSource: this.mediaSource,
737      currentTime: this.tech_.currentTime.bind(this.tech_),
738      seekable: function seekable() {
739        return _this.seekable();
740      },
741      seeking: function seeking() {
742        return _this.tech_.seeking();
743      },
744      setCurrentTime: function setCurrentTime(a) {
745        return _this.tech_.setCurrentTime(a);
746      },
747      hasPlayed: function hasPlayed() {
748        return _this.tech_.played().length !== 0;
749      },
750      bandwidth: bandwidth
751    };
752
753    // setup playlist loaders
754    this.masterPlaylistLoader_ = new _playlistLoader2['default'](url, this.hls_, this.withCredentials);
755    this.setupMasterPlaylistLoaderListeners_();
756    this.audioPlaylistLoader_ = null;
757
758    // setup segment loaders
759    // combined audio/video or just video when alternate audio track is selected
760    this.mainSegmentLoader_ = new _segmentLoader2['default'](segmentLoaderOptions);
761    // alternate audio track
762    this.audioSegmentLoader_ = new _segmentLoader2['default'](segmentLoaderOptions);
763    this.setupSegmentLoaderListeners_();
764
765    this.masterPlaylistLoader_.start();
766  }
767
768  /**
769   * Register event handlers on the master playlist loader. A helper
770   * function for construction time.
771   *
772   * @private
773   */
774
775  _createClass(MasterPlaylistController, [{
776    key: 'setupMasterPlaylistLoaderListeners_',
777    value: function setupMasterPlaylistLoaderListeners_() {
778      var _this2 = this;
779
780      this.masterPlaylistLoader_.on('loadedmetadata', function () {
781        var media = _this2.masterPlaylistLoader_.media();
782        var requestTimeout = _this2.masterPlaylistLoader_.targetDuration * 1.5 * 1000;
783
784        _this2.requestOptions_.timeout = requestTimeout;
785
786        // if this isn't a live video and preload permits, start
787        // downloading segments
788        if (media.endList && _this2.tech_.preload() !== 'none') {
789          _this2.mainSegmentLoader_.playlist(media, _this2.requestOptions_);
790          _this2.mainSegmentLoader_.expired(_this2.masterPlaylistLoader_.expired_);
791          _this2.mainSegmentLoader_.load();
792        }
793
794        try {
795          _this2.setupSourceBuffers_();
796        } catch (e) {
797          _videoJs2['default'].log.warn('Failed to create SourceBuffers', e);
798          return _this2.mediaSource.endOfStream('decode');
799        }
800        _this2.setupFirstPlay();
801
802        _this2.fillAudioTracks_();
803        _this2.setupAudio();
804        _this2.trigger('audioupdate');
805
806        _this2.trigger('selectedinitialmedia');
807      });
808
809      this.masterPlaylistLoader_.on('loadedplaylist', function () {
810        var updatedPlaylist = _this2.masterPlaylistLoader_.media();
811        var seekable = undefined;
812
813        if (!updatedPlaylist) {
814          // select the initial variant
815          _this2.initialMedia_ = _this2.selectPlaylist();
816          _this2.masterPlaylistLoader_.media(_this2.initialMedia_);
817          return;
818        }
819
820        if (_this2.useCueTags_) {
821          _this2.updateAdCues_(updatedPlaylist, _this2.masterPlaylistLoader_.expired_);
822        }
823
824        // TODO: Create a new event on the PlaylistLoader that signals
825        // that the segments have changed in some way and use that to
826        // update the SegmentLoader instead of doing it twice here and
827        // on `mediachange`
828        _this2.mainSegmentLoader_.playlist(updatedPlaylist, _this2.requestOptions_);
829        _this2.mainSegmentLoader_.expired(_this2.masterPlaylistLoader_.expired_);
830        _this2.updateDuration();
831
832        // update seekable
833        seekable = _this2.seekable();
834        if (!updatedPlaylist.endList && seekable.length !== 0) {
835          _this2.mediaSource.addSeekableRange_(seekable.start(0), seekable.end(0));
836        }
837      });
838
839      this.masterPlaylistLoader_.on('error', function () {
840        _this2.blacklistCurrentPlaylist(_this2.masterPlaylistLoader_.error);
841      });
842
843      this.masterPlaylistLoader_.on('mediachanging', function () {
844        _this2.mainSegmentLoader_.abort();
845        _this2.mainSegmentLoader_.pause();
846      });
847
848      this.masterPlaylistLoader_.on('mediachange', function () {
849        var media = _this2.masterPlaylistLoader_.media();
850        var requestTimeout = _this2.masterPlaylistLoader_.targetDuration * 1.5 * 1000;
851        var activeAudioGroup = undefined;
852        var activeTrack = undefined;
853
854        // If we don't have any more available playlists, we don't want to
855        // timeout the request.
856        if (_this2.masterPlaylistLoader_.isLowestEnabledRendition_()) {
857          _this2.requestOptions_.timeout = 0;
858        } else {
859          _this2.requestOptions_.timeout = requestTimeout;
860        }
861
862        // TODO: Create a new event on the PlaylistLoader that signals
863        // that the segments have changed in some way and use that to
864        // update the SegmentLoader instead of doing it twice here and
865        // on `loadedplaylist`
866        _this2.mainSegmentLoader_.playlist(media, _this2.requestOptions_);
867        _this2.mainSegmentLoader_.expired(_this2.masterPlaylistLoader_.expired_);
868        _this2.mainSegmentLoader_.load();
869
870        // if the audio group has changed, a new audio track has to be
871        // enabled
872        activeAudioGroup = _this2.activeAudioGroup();
873        activeTrack = activeAudioGroup.filter(function (track) {
874          return track.enabled;
875        })[0];
876        if (!activeTrack) {
877          _this2.setupAudio();
878          _this2.trigger('audioupdate');
879        }
880
881        _this2.tech_.trigger({
882          type: 'mediachange',
883          bubbles: true
884        });
885      });
886    }
887
888    /**
889     * Register event handlers on the segment loaders. A helper function
890     * for construction time.
891     *
892     * @private
893     */
894  }, {
895    key: 'setupSegmentLoaderListeners_',
896    value: function setupSegmentLoaderListeners_() {
897      var _this3 = this;
898
899      this.mainSegmentLoader_.on('progress', function () {
900        // figure out what stream the next segment should be downloaded from
901        // with the updated bandwidth information
902        _this3.masterPlaylistLoader_.media(_this3.selectPlaylist());
903
904        _this3.trigger('progress');
905      });
906
907      this.mainSegmentLoader_.on('error', function () {
908        _this3.blacklistCurrentPlaylist(_this3.mainSegmentLoader_.error());
909      });
910
911      this.audioSegmentLoader_.on('error', function () {
912        _videoJs2['default'].log.warn('Problem encountered with the current alternate audio track' + '. Switching back to default.');
913        _this3.audioSegmentLoader_.abort();
914        _this3.audioPlaylistLoader_ = null;
915        _this3.setupAudio();
916      });
917    }
918  }, {
919    key: 'handleAudioinfoUpdate_',
920    value: function handleAudioinfoUpdate_(event) {
921      if (Hls.supportsAudioInfoChange_() || !this.audioInfo_ || !
921objectChanged(this.audioInfo_, event.info)) {
922        this.audioInfo_ = event.info;
923        return;
924      }
925
926      var error = 'had different audio properties (channels, sample rate, etc.) ' + 'or changed in some other way.  This behavior is currently ' + 'unsupported in Firefox 48 and below due to an issue: \n\n' + 'https://bugzilla.mozilla.org/show_bug.cgi?id=1247138\n\n';
927
928      var enabledIndex = this.activeAudioGroup().map(function (track) {
929        return track.enabled;
930      }).indexOf(true);
931      var enabledTrack = this.activeAudioGroup()[enabledIndex];
932      var defaultTrack = this.activeAudioGroup().filter(function (track) {
933        return track.properties_ && track.properties_['default'];
934      })[0];
935
936      // they did not switch audiotracks
937      // blacklist the current playlist
938      if (!this.audioPlaylistLoader_) {
939        error = 'The rendition that we tried to switch to ' + error + 'Unfortunately that means we will have to blacklist ' + 'the current playlist and switch to another. Sorry!';
940        this.blacklistCurrentPlaylist();
941      } else {
942        error = 'The audio track \'' + enabledTrack.label + '\' that we tried to ' + ('switch to ' + error + ' Unfortunately this means we will have to ') + ('return you to the main track \'' + defaultTrack.label + '\'. Sorry!');
943        defaultTrack.enabled = true;
944        this.activeAudioGroup().splice(enabledIndex, 1);
945        this.trigger('audioupdate');
946      }
947
948      _videoJs2['default'].log.warn(error);
949      this.setupAudio();
950    }
951
952    /**
953     * get the total number of media requests from the `audiosegmentloader_`
954     * and the `mainSegmentLoader_`
955     *
956     * @private
957     */
958  }, {
959    key: 'mediaRequests_',
960    value: function mediaRequests_() {
961      return this.audioSegmentLoader_.mediaRequests + this.mainSegmentLoader_.mediaRequests;
962    }
963
964    /**
965     * get the total time that media requests have spent trnasfering
966     * from the `audiosegmentloader_` and the `mainSegmentLoader_`
967     *
968     * @private
969     */
970  }, {
971    key: 'mediaTransferDuration_',
972    value: function mediaTransferDuration_() {
973      return this.audioSegmentLoader_.mediaTransferDuration + this.mainSegmentLoader_.mediaTransferDuration;
974    }
975
976    /**
977     * get the total number of bytes transfered during media requests
978     * from the `audiosegmentloader_` and the `mainSegmentLoader_`
979     *
980     * @private
981     */
982  }, {
983    key: 'mediaBytesTransferred_',
984    value: function mediaBytesTransferred_() {
985      return this.audioSegmentLoader_.mediaBytesTransferred + this.mainSegmentLoader_.mediaBytesTransferred;
986    }
987
988    /**
989     * fill our internal list of HlsAudioTracks with data from
990     * the master playlist or use a default
991     *
992     * @private
993     */
994  }, {
995    key: 'fillAudioTracks_',
996    value: function fillAudioTracks_() {
997      var master = this.master();
998      var mediaGroups = master.mediaGroups || {};
999
1000      // force a default if we have none or we are not
1001      // in html5 mode (the only mode to support more than one
1002      // audio track)
1003      if (!mediaGroups || !mediaGroups.AUDIO || Object.keys(mediaGroups.AUDIO).length === 0 || this.mode_ !== 'html5') {
1004        // "main" audio group, track name "default"
1005        mediaGroups.AUDIO = { main: { 'default': { 'default': true } } };
1006      }
1007
1008      for (var mediaGroup in mediaGroups.AUDIO) {
1009        if (!this.audioGroups_[mediaGroup]) {
1010          this.audioGroups_[mediaGroup] = [];
1011        }
1012
1013        for (var label in mediaGroups.AUDIO[mediaGroup]) {
1014          var properties = mediaGroups.AUDIO[mediaGroup][label];
1015          var track = new _videoJs2['default'].AudioTrack({
1016            id: label,
1017            kind: properties['default'] ? 'main' : 'alternative',
1018            enabled: false,
1019            language: properties.language,
1020            label: label
1021          });
1022
1023          track.properties_ = properties;
1024          this.audioGroups_[mediaGroup].push(track);
1025        }
1026      }
1027
1028      // enable the default active track
1029      (this.activeAudioGroup().filter(function (audioTrack) {
1030        return audioTrack.properties_['default'];
1031      })[0] || this.activeAudioGroup()[0]).enabled = true;
1032    }
1033
1034    /**
1035     * Call load on our SegmentLoaders
1036     */
1037  }, {
1038    key: 'load',
1039    value: function load() {
1040      this.mainSegmentLoader_.load();
1041      if (this.audioPlaylistLoader_) {
1042        this.audioSegmentLoader_.load();
1043      }
1044    }
1045
1046    /**
1047     * Returns the audio group for the currently active primary
1048     * media playlist.
1049     */
1050  }, {
1051    key: 'activeAudioGroup',
1052    value: function activeAudioGroup() {
1053      var videoPlaylist = this.masterPlaylistLoader_.media();
1054      var result = undefined;
1055
1056      if (videoPlaylist.attributes && videoPlaylist.attributes.AUDIO) {
1057        result = this.audioGroups_[videoPlaylist.attributes.AUDIO];
1058      }
1059
1060      return result || this.audioGroups_.main;
1061    }
1062
1063    /**
1064     * Determine the correct audio rendition based on the active
1065     * AudioTrack and initialize a PlaylistLoader and SegmentLoader if
1066     * necessary. This method is called once automatically before
1067     * playback begins to enable the default audio track and should be
1068     * invoked again if the track is changed.
1069     */
1070  }, {
1071    key: 'setupAudio',
1072    value: function setupAudio() {
1073      var _this4 = this;
1074
1075      // determine whether seperate loaders are required for the audio
1076      // rendition
1077      var audioGroup = this.activeAudioGroup();
1078      var track = audioGroup.filter(function (audioTrack) {
1079        return audioTrack.enabled;
1080      })[0];
1081
1082      if (!track) {
1083        track = audioGroup.filter(function (audioTrack) {
1084          return audioTrack.properties_['default'];
1085        })[0] || audioGroup[0];
1086        track.enabled = true;
1087      }
1088
1089      // stop playlist and segment loading for audio
1090      if (this.audioPlaylistLoader_) {
1091        this.audioPlaylistLoader_.dispose();
1092        this.audioPlaylistLoader_ = null;
1093      }
1094      this.audioSegmentLoader_.pause();
1095      this.audioSegmentLoader_.clearBuffer();
1096
1097      if (!track.properties_.resolvedUri) {
1098        return;
1099      }
1100
1101      // startup playlist and segment loaders for the enabled audio
1102      // track
1103      this.audioPlaylistLoader_ = new _playlistLoader2['default'](track.properties_.resolvedUri, this.hls_, this.withCredentials);
1104      this.audioPlaylistLoader_.start();
1105
1106      this.audioPlaylistLoader_.on('loadedmetadata', function () {
1107        var audioPlaylist = _this4.audioPlaylistLoader_.media();
1108
1109        _this4.audioSegmentLoader_.playlist(audioPlaylist, _this4.requestOptions_);
1110
1111        // if the video is already playing, or if this isn't a live video and preload
1112        // permits, start downloading segments
1113        if (!_this4.tech_.paused() || audioPlaylist.endList && _this4.tech_.preload() !== 'none') {
1114          _this4.audioSegmentLoader_.load();
1115        }
1116
1117        if (!audioPlaylist.endList) {
1118          // trigger the playlist loader to start "expired time"-tracking
1119          _this4.audioPlaylistLoader_.trigger('firstplay');
1120        }
1121      });
1122
1123      this.audioPlaylistLoader_.on('loadedplaylist', function () {
1124        var updatedPlaylist = undefined;
1125
1126        if (_this4.audioPlaylistLoader_) {
1127          updatedPlaylist = _this4.audioPlaylistLoader_.media();
1128        }
1129
1130        if (!updatedPlaylist) {
1131          // only one playlist to select
1132          _this4.audioPlaylistLoader_.media(_this4.audioPlaylistLoader_.playlists.master.playlists[0]);
1133          return;
1134        }
1135
1136        _this4.audioSegmentLoader_.playlist(updatedPlaylist, _this4.requestOptions_);
1137      });
1138
1139      this.audioPlaylistLoader_.on('error', function () {
1140        _videoJs2['default'].log.warn('Problem encountered loading the alternate audio track' + '. Switching back to default.');
1141        _this4.audioSegmentLoader_.abort();
1142        _this4.setupAudio();
1143      });
1144    }
1145
1146    /**
1147     * Re-tune playback quality level for the current player
1148     * conditions. This method may perform destructive actions, like
1149     * removing already buffered content, to readjust the currently
1150     * active playlist quickly.
1151     *
1152     * @private
1153     */
1154  }, {
1155    key: 'fastQualityChange_',
1156    value: function fastQualityChange_() {
1157      var media = this.selectPlaylist();
1158
1159      if (media !== this.masterPlaylistLoader_.media()) {
1160        this.masterPlaylistLoader_.media(media);
1161        this.mainSegmentLoader_.sourceUpdater_.remove(this.tech_.currentTime() + 5, Infinity);
1162      }
1163    }
1164
1165    /**
1166     * Begin playback.
1167     */
1168  }, {
1169    key: 'play',
1170    value: function play() {
1171      if (this.setupFirstPlay()) {
1172        return;
1173      }
1174
1175      if (this.tech_.ended()) {
1176        this.tech_.setCurrentTime(0);
1177      }
1178
1179      this.load();
1180
1181      // if the viewer has paused and we fell out of the live window,
1182      // seek forward to the earliest available position
1183      if (this.tech_.duration() === Infinity) {
1184        if (this.tech_.currentTime() < this.tech_.seekable().start(0)) {
1185          return this.tech_.setCurrentTime(this.tech_.seekable().start(0));
1186        }
1187      }
1188    }
1189
1190    /**
1191     * Seek to the latest media position if this is a live video and the
1192     * player and video are loaded and initialized.
1193     */
1194  }, {
1195    key: 'setupFirstPlay',
1196    value: function setupFirstPlay() {
1197      var seekable = undefined;
1198      var media = this.masterPlaylistLoader_.media();
1199
1200      // check that everything is ready to begin buffering
1201      // 1) the active media playlist is available
1202      if (media &&
1203      // 2) the video is a live stream
1204      !media.endList &&
1205
1206      // 3) the player is not paused
1207      !this.tech_.paused() &&
1208
1209      // 4) the player has not started playing
1210      !this.hasPlayed_) {
1211
1212        // trigger the playlist loader to start "expired time"-tracking
1213        this.masterPlaylistLoader_.trigger('firstplay');
1214        this.hasPlayed_ = true;
1215
1216        // seek to the latest media position for live videos
1217        seekable = this.seekable();
1218        if (seekable.length) {
1219          this.tech_.setCurrentTime(seekable.end(0));
1220        }
1221
1222        // now that we seeked to the current time, load the segment
1223        this.load();
1224
1225        return true;
1226      }
1227      return false;
1228    }
1229
1230    /**
1231     * handle the sourceopen event on the MediaSource
1232     *
1233     * @private
1234     */
1235  }, {
1236    key: 'handleSourceOpen_',
1237    value: function handleSourceOpen_() {
1238      // Only attempt to create the source buffer if none already exist.
1239      // handleSourceOpen is also called when we are "re-opening" a source buffer
1240      // after `endOfStream` has been called (in response to a seek for instance)
1241      try {
1242        this.setupSourceBuffers_();
1243      } catch (e) {
1244        _videoJs2['default'].log.warn('Failed to create Source Buffers', e);
1245        return this.mediaSource.endOfStream('decode');
1246      }
1247
1248      // if autoplay is enabled, begin playback. This is duplicative of
1249      // code in video.js but is required because play() must be invoked
1250      // *after* the media source has opened.
1251      if (this.tech_.autoplay()) {
1252        this.tech_.play();
1253      }
1254
1255      this.trigger('sourceopen');
1256    }
1257
1258    /**
1259     * Blacklists a playlist when an error occurs for a set amount of time
1260     * making it unavailable for selection by the rendition selection algorithm
1261     * and then forces a new playlist (rendition) selection.
1262     *
1263     * @param {Object=} error an optional error that may include the playlist
1264     * to blacklist
1265     */
1266  }, {
1267    key: 'blacklistCurrentPlaylist',
1268    value: function blacklistCurrentPlaylist() {
1269      var error = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
1270
1271      var currentPlaylist = undefined;
1272      var nextPlaylist = undefined;
1273
1274      // If the `error` was generated by the playlist loader, it will contain
1275      // the playlist we were trying to load (but failed) and that should be
1276      // blacklisted instead of the currently selected playlist which is likely
1277      // out-of-date in this scenario
1278      currentPlaylist = error.playlist || this.masterPlaylistLoader_.media();
1279
1280      // If there is no current playlist, then an error occurred while we were
1281      // trying to load the master OR while we were disposing of the tech
1282      if (!currentPlaylist) {
1283        this.error = error;
1284        return this.mediaSource.endOfStream('network');
1285      }
1286
1287      // Blacklist this playlist
1288      currentPlaylist.excludeUntil = Date.now() + BLACKLIST_DURATION;
1289
1290      // Select a new playlist
1291      nextPlaylist = this.selectPlaylist();
1292
1293      if (nextPlaylist) {
1294        _videoJs2['default'].log.warn('Problem encountered with the current ' + 'HLS playlist. Switching to another playlist.');
1295
1296        return this.masterPlaylistLoader_.media(nextPlaylist);
1297      }
1298      _videoJs2['default'].log.warn('Problem encountered with the current ' + 'HLS playlist. No suitable alternatives found.');
1299      // We have no more playlists we can select so we must fail
1300      this.error = error;
1301      return this.mediaSource.endOfStream('network');
1302    }
1303
1304    /**
1305     * Pause all segment loaders
1306     */
1307  }, {
1308    key: 'pauseLoading',
1309    value: function pauseLoading() {
1310      this.mainSegmentLoader_.pause();
1311      if (this.audioPlaylistLoader_) {
1312        this.audioSegmentLoader_.pause();
1313      }
1314    }
1315
1316    /**
1317     * set the current time on all segment loaders
1318     *
1319     * @param {TimeRange} currentTime the current time to set
1320     * @return {TimeRange} the current time
1321     */
1322  }, {
1323    key: 'setCurrentTime',
1324    value: function setCurrentTime(currentTime) {
1325      var buffered = _ranges2['default'].findRange(this.tech_.buffered(), currentTime);
1326
1327      if (!(this.masterPlaylistLoader_ && this.masterPlaylistLoader_.media())) {
1328        // return immediately if the metadata is not ready yet
1329        return 0;
1330      }
1331
1332      // it's clearly an edge-case but don't thrown an error if asked to
1333      // seek within an empty playlist
1334      if (!this.masterPlaylistLoader_.media().segments) {
1335        return 0;
1336      }
1337
1338      // if the seek location is already buffered, continue buffering as
1339      // usual
1340      if (buffered && buffered.length) {
1341        return currentTime;
1342      }
1343
1344      // cancel outstanding requests so we begin buffering at the new
1345      // location
1346      this.mainSegmentLoader_.abort();
1347      if (this.audioPlaylistLoader_) {
1348        this.audioSegmentLoader_.abort();
1349      }
1350
1351      if (!this.tech_.paused()) {
1352        this.mainSegmentLoader_.load();
1353        if (this.audioPlaylistLoader_) {
1354          this.audioSegmentLoader_.load();
1355        }
1356      }
1357    }
1358
1359    /**
1360     * get the current duration
1361     *
1362     * @return {TimeRange} the duration
1363     */
1364  }, {
1365    key: 'duration',
1366    value: function duration() {
1367      if (!this.masterPlaylistLoader_) {
1368        return 0;
1369      }
1370
1371      if (this.mediaSource) {
1372        return this.mediaSource.duration;
1373      }
1374
1375      return Hls.Playlist.duration(this.masterPlaylistLoader_.media());
1376    }
1377
1378    /**
1379     * check the seekable range
1380     *
1381     * @return {TimeRange} the seekable range
1382     */
1383  }, {
1384    key: 'seekable',
1385    value: function seekable() {
1386      var media = undefined;
1387      var mainSeekable = undefined;
1388      var audioSeekable = undefined;
1389
1390      if (!this.masterPlaylistLoader_) {
1391        return _videoJs2['default'].createTimeRanges();
1392      }
1393      media = this.masterPlaylistLoader_.media();
1394      if (!media) {
1395        return _videoJs2['default'].createTimeRanges();
1396      }
1397
1398      mainSeekable = Hls.Playlist.seekable(media, this.masterPlaylistLoader_.expired_);
1399      if (mainSeekable.length === 0) {
1400        return mainSeekable;
1401      }
1402
1403      if (this.audioPlaylistLoader_) {
1404        audioSeekable = Hls.Playlist.seekable(this.audioPlaylistLoader_.media(), this.audioPlaylistLoader_.expired_);
1405        if (audioSeekable.length === 0) {
1406          return audioSeekable;
1407        }
1408      }
1409
1410      if (!audioSeekable) {
1411        // seekable has been calculated based on buffering video data so it
1412        // can be returned directly
1413        return mainSeekable;
1414      }
1415
1416      return _videoJs2['default'].createTimeRanges([[audioSeekable.start(0) > mainSeekable.start(0) ? audioSeekable.start(0) : mainSeekable.start(0), audioSeekable.end(0) < mainSeekable.end(0) ? audioSeekable.end(0) : mainSeekable.end(0)]]);
1417    }
1418
1419    /**
1420     * Update the player duration
1421     */
1422  }, {
1423    key: 'updateDuration',
1424    value: function updateDuration() {
1425      var _this5 = this;
1426
1427      var oldDuration = this.mediaSource.duration;
1428      var newDuration = Hls.Playlist.duration(this.masterPlaylistLoader_.media());
1429      var buffered = this.tech_.buffered();
1430      var setDuration = function setDuration() {
1431        _this5.mediaSource.duration = newDuration;
1432        _this5.tech_.trigger('durationchange');
1433
1434        _this5.mediaSource.removeEventListener('sourceopen', setDuration);
1435      };
1436
1437      if (buffered.length > 0) {
1438        newDuration = Math.max(newDuration, buffered.end(buffered.length - 1));
1439      }
1440
1441      // if the duration has changed, invalidate the cached value
1442      if (oldDuration !== newDuration) {
1443        // update the duration
1444        if (this.mediaSource.readyState !== 'open') {
1445          this.mediaSource.addEventListener('sourceopen', setDuration);
1446        } else {
1447          setDuration();
1448        }
1449      }
1450    }
1451
1452    /**
1453     * dispose of the MasterPlaylistController and everything
1454     * that it controls
1455     */
1456  }, {
1457    key: 'dispose',
1458    value: function dispose() {
1459      this.masterPlaylistLoader_.dispose();
1460      this.mainSegmentLoader_.dispose();
1461
1462      this.audioSegmentLoader_.dispose();
1463    }
1464
1465    /**
1466     * return the master playlist object if we have one
1467     *
1468     * @return {Object} the master playlist object that we parsed
1469     */
1470  }, {
1471    key: 'master',
1472    value: function master() {
1473      return this.masterPlaylistLoader_.master;
1474    }
1475
1476    /**
1477     * return the currently selected playlist
1478     *
1479     * @return {Object} the currently selected playlist object that we parsed
1480     */
1481  }, {
1482    key: 'media',
1483    value: function media() {
1484      // playlist loader will not return media if it has not been fully loaded
1485      return this.masterPlaylistLoader_.media() || this.initialMedia_;
1486    }
1487
1488    /**
1489     * setup our internal source buffers on our segment Loaders
1490     *
1491     * @private
1492     */
1493  }, {
1494    key: 'setupSourceBuffers_',
1495    value: function setupSourceBuffers_() {
1496      var media = this.masterPlaylistLoader_.media();
1497      var mimeTypes = undefined;
1498
1499      // wait until a media playlist is available and the Media Source is
1500      // attached
1501      if (!media || this.mediaSource.readyState !== 'open') {
1502        return;
1503      }
1504
1505      mimeTypes = mimeTypesForPlaylist_(this.masterPlaylistLoader_.master, media);
1506      if (mimeTypes.length < 1) {
1507        this.error = 'No compatible SourceBuffer configuration for the variant stream:' + media.resolvedUri;
1508        return this.mediaSource.endOfStream('decode');
1509      }
1510      this.mainSegmentLoader_.mimeType(mimeTypes[0]);
1511      if (mimeTypes[1]) {
1512        this.audioSegmentLoader_.mimeType(mimeTypes[1]);
1513      }
1514
1515      // exclude any incompatible variant streams from future playlist
1516      // selection
1517      this.excludeIncompatibleVariants_(media);
1518    }
1519
1520    /**
1521     * Blacklist playlists that are known to be codec or
1522     * stream-incompatible with the SourceBuffer configuration. For
1523     * instance, Media Source Extensions would cause the video element to
1524     * stall waiting for video data if you switched from a variant with
1525     * video and audio to an audio-only one.
1526     *
1527     * @param {Object} media a media playlist compatible with the current
1528     * set of SourceBuffers. Variants in the current master playlist that
1529     * do not appear to have compatible codec or stream configurations
1530     * will be excluded from the default playlist selection algorithm
1531     * indefinitely.
1532     * @private
1533     */
1534  }, {
1535    key: 'excludeIncompatibleVariants_',
1536    value: function excludeIncompatibleVariants_(media) {
1537      var master = this.masterPlaylistLoader_.master;
1538      var codecCount = 2;
1539      var videoCodec = null;
1540      var audioProfile = null;
1541      var codecs = undefined;
1542
1543      if (media.attributes && media.attributes.CODECS) {
1544        codecs = parseCodecs(media.attributes.CODECS);
1545        videoCodec = codecs.videoCodec;
1546        audioProfile = codecs.audioProfile;
1547        codecCount = codecs.codecCount;
1548      }
1549      master.playlists.forEach(function (variant) {
1550        var variantCodecs = {
1551          codecCount: 2,
1552          videoCodec: null,
1553          audioProfile: null
1554        };
1555
1556        if (variant.attributes && variant.attributes.CODECS) {
1557          var codecString = variant.attributes.CODECS;
1558
1559          variantCodecs = parseCodecs(codecString);
1560          if (window.MediaSource && window.MediaSource.isTypeSupported && !window.MediaSource.isTypeSupported('video/mp4; codecs="' + codecString + '"')) {
1561            variant.excludeUntil = Infinity;
1562          }
1563        }
1564
1565        // if the streams differ in the presence or absence of audio or
1566        // video, they are incompatible
1567        if (variantCodecs.codecCount !== codecCount) {
1568          variant.excludeUntil = Infinity;
1569        }
1570
1571        // if h.264 is specified on the current playlist, some flavor of
1572        // it must be specified on all compatible variants
1573        if (variantCodecs.videoCodec !== videoCodec) {
1574          variant.excludeUntil = Infinity;
1575        }
1576        // HE-AAC ("mp4a.40.5") is incompatible with all other versions of
1577        // AAC audio in Chrome 46. Don't mix the two.
1578        if (variantCodecs.audioProfile === '5' && audioProfile !== '5' || audioProfile === '5' && variantCodecs.audioProfile !== '5') {
1579          variant.excludeUntil = Infinity;
1580        }
1581      });
1582    }
1583  }, {
1584    key: 'updateAdCues_',
1585    value: function updateAdCues_(media) {
1586      var offset = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
1587
1588      _adCueTags2['default'].updateAdCues(media, this.cueTagsTrack_, offset);
1589    }
1590  }]);
1591
1592  return MasterPlaylistController;
1593})(_videoJs2['default'].EventTarget);
1594
1595exports.MasterPlaylistController = MasterPlaylistController;
1596}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1597},{"./ad-cue-tags":1,"./playlist-loader":6,"./ranges":8,"./segment-loader":11}],6:[function(require,module,exports){
1598(function (global){
1599/**
1600 * @file playlist-loader.js
1601 *
1602 * A state machine that manages the loading, caching, and updating of
1603 * M3U8 playlists.
1604 *
1605 */
1606'use strict';
1607
1608Object.defineProperty(exports, '__esModule', {
1609  value: true
1610});
1611
1612function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
1613
1614var _resolveUrl = require('./resolve-url');
1615
1616var _resolveUrl2 = _interopRequireDefault(_resolveUrl);
1617
1618var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
1619
1620var _stream = require('./stream');
1621
1622var _stream2 = _interopRequireDefault(_stream);
1623
1624var _m3u8Parser = require('m3u8-parser');
1625
1626var _m3u8Parser2 = _interopRequireDefault(_m3u8Parser);
1627
1628var _globalWindow = require('global/window');
1629
1630var _globalWindow2 = _interopRequireDefault(_globalWindow);
1631
1632/**
1633  * Returns a new array of segments that is the result of merging
1634  * properties from an older list of segments onto an updated
1635  * list. No properties on the updated playlist will be overridden.
1636  *
1637  * @param {Array} original the outdated list of segments
1638  * @param {Array} update the updated list of segments
1639  * @param {Number=} offset the index of the first update
1640  * segment in the original segment list. For non-live playlists,
1641  * this should always be zero and does not need to be
1642  * specified. For live playlists, it should be the difference
1643  * between the media sequence numbers in the original and updated
1644  * playlists.
1645  * @return a list of merged segment objects
1646  */
1647var updateSegments = function updateSegments(original, update, offset) {
1648  var result = update.slice();
1649  var length = undefined;
1650  var i = undefined;
1651
1652  offset = offset || 0;
1653  length = Math.min(original.length, update.length + offset);
1654
1655  for (i = offset; i < length; i++) {
1656    result[i - offset] = (0, _videoJs.mergeOptions)(original[i], result[i - offset]);
1657  }
1658  return result;
1659};
1660
1661/**
1662  * Returns a new master playlist that is the result of merging an
1663  * updated media playlist into the original version. If the
1664  * updated media playlist does not match any of the playlist
1665  * entries in the original master playlist, null is returned.
1666  *
1667  * @param {Object} master a parsed master M3U8 object
1668  * @param {Object} media a parsed media M3U8 object
1669  * @return {Object} a new object that represents the original
1670  * master playlist with the updated media playlist merged in, or
1671  * null if the merge produced no change.
1672  */
1673var updateMaster = function updateMaster(master, media) {
1674  var changed = false;
1675  var result = (0, _videoJs.mergeOptions)(master, {});
1676  var i = master.playlists.length;
1677  var playlist = undefined;
1678  var segment = undefined;
1679  var j = undefined;
1680
1681  while (i--) {
1682    playlist = result.playlists[i];
1683    if (playlist.uri === media.uri) {
1684      // consider the playlist unchanged if the number of segments
1685      // are equal and the media sequence number is unchanged
1686      if (playlist.segments && media.segments && playlist.segments.length === media.segments.length && playlist.mediaSequence === media.mediaSequence) {
1687        continue;
1688      }
1689
1690      result.playlists[i] = (0, _videoJs.mergeOptions)(playlist, media);
1691      result.playlists[media.uri] = result.playlists[i];
1692
1693      // if the update could overlap existing segment information,
1694      // merge the two lists
1695      if (playlist.segments) {
1696        result.playlists[i].segments = updateSegments(playlist.segments, media.segments, media.mediaSequence - playlist.mediaSequence);
1697      }
1698      // resolve any missing segment and key URIs
1699      j = 0;
1700      if (result.playlists[i].segments) {
1701        j = result.playlists[i].segments.length;
1702      }
1703      while (j--) {
1704        segment = result.playlists[i].segments[j];
1705        if (!segment.resolvedUri) {
1706          segment.resolvedUri = (0, _resolveUrl2['default'])(playlist.resolvedUri, segment.uri);
1707        }
1708        if (segment.key && !segment.key.resolvedUri) {
1709          segment.key.resolvedUri = (0, _resolveUrl2['default'])(playlist.resolvedUri, segment.key.uri);
1710        }
1711        if (segment.map && !segment.map.resolvedUri) {
1712          segment.map.resolvedUri = (0, _resolveUrl2['default'])(playlist.resolvedUri, segment.map.uri);
1713        }
1714      }
1715      changed = true;
1716    }
1717  }
1718  return changed ? result : null;
1719};
1720
1721/**
1722 * Load a playlist from a remote loacation
1723 *
1724 * @class PlaylistLoader
1725 * @extends Stream
1726 * @param {String} srcUrl the url to start with
1727 * @param {Boolean} withCredentials the withCredentials xhr option
1728 * @constructor
1729 */
1730var PlaylistLoader = function PlaylistLoader(srcUrl, hls, withCredentials) {
1731  var _this = this;
1732
1733  /* eslint-disable consistent-this */
1734  var loader = this;
1735  /* eslint-enable consistent-this */
1736  var dispose = undefined;
1737  var mediaUpdateTimeout = undefined;
1738  var request = undefined;
1739  var playlistRequestError = undefined;
1740  var haveMetadata = undefined;
1741
1742  PlaylistLoader.prototype.constructor.call(this);
1743
1744  this.hls_ = hls;
1745
1746  // a flag that disables "expired time"-tracking this setting has
1747  // no effect when not playing a live stream
1748  this.trackExpiredTime_ = false;
1749
1750  if (!srcUrl) {
1751    throw new Error('A non-empty playlist URL is required');
1752  }
1753
1754  playlistRequestError = function (xhr, url, startingState) {
1755    loader.setBandwidth(request || xhr);
1756
1757    // any in-flight request is now finished
1758    request = null;
1759
1760    if (startingState) {
1761      loader.state = startingState;
1762    }
1763
1764    loader.error = {
1765      playlist: loader.master.playlists[url],
1766      status: xhr.status,
1767      message: 'HLS playlist request error at URL: ' + url,
1768      responseText: xhr.responseText,
1769      code: xhr.status >= 500 ? 4 : 2
1770    };
1771
1772    loader.trigger('error');
1773  };
1774
1775  // update the playlist loader's state in response to a new or
1776  // updated playlist.
1777  haveMetadata = function (xhr, url) {
1778    var parser = undefined;
1779    var refreshDelay = undefined;
1780    var update = undefined;
1781
1782    loader.setBandwidth(request || xhr);
1783
1784    // any in-flight request is now finished
1785    request = null;
1786
1787    loader.state = 'HAVE_METADATA';
1788
1789    parser = new _m3u8Parser2['default'].Parser();
1790    parser.push(xhr.responseText);
1791    parser.end();
1792    parser.manifest.uri = url;
1793
1794    // merge this playlist into the master
1795    update = updateMaster(loader.master, parser.manifest);
1796    refreshDelay = (parser.manifest.targetDuration || 10) * 1000;
1797    loader.targetDuration = parser.manifest.targetDuration;
1798    if (update) {
1799      loader.master = update;
1800      loader.updateMediaPlaylist_(parser.manifest);
1801    } else {
1802      // if the playlist is unchanged since the last reload,
1803      // try again after half the target duration
1804      refreshDelay /= 2;
1805    }
1806
1807    // refresh live playlists after a target duration passes
1808    if (!loader.media().endList) {
1809      _globalWindow2['default'].clearTimeout(mediaUpdateTimeout);
1810      mediaUpdateTimeout = _globalWindow2['default'].setTimeout(function () {
1811        loader.trigger('mediaupdatetimeout');
1812      }, refreshDelay);
1813    }
1814
1815    loader.trigger('loadedplaylist');
1816  };
1817
1818  // initialize the loader state
1819  loader.state = 'HAVE_NOTHING';
1820
1821  // track the time that has expired from the live window
1822  // this allows the seekable start range to be calculated even if
1823  // all segments with timing information have expired
1824  this.expired_ = 0;
1825
1826  // capture the prototype dispose function
1827  dispose = this.dispose;
1828
1829  /**
1830   * Abort any outstanding work and clean up.
1831   */
1832  loader.dispose = function () {
1833    loader.stopRequest();
1834    _globalWindow2['default'].clearTimeout(mediaUpdateTimeout);
1835    dispose.call(this);
1836  };
1837
1838  loader.stopRequest = function () {
1839    if (request) {
1840      var oldRequest = request;
1841
1842      request = null;
1843      oldRequest.onreadystatechange = null;
1844      oldRequest.abort();
1845    }
1846  };
1847
1848  /**
1849   * Returns the number of enabled playlists on the master playlist object
1850   *
1851   * @return {Number} number of eneabled playlists
1852   */
1853  loader.enabledPlaylists_ = function () {
1854    return loader.master.playlists.filter(function (element, index, array) {
1855      return !element.excludeUntil || element.excludeUntil <= Date.now();
1856    }).length;
1857  };
1858
1859  /**
1860   * Returns whether the current playlist is the lowest rendition
1861   *
1862   * @return {Boolean} true if on lowest rendition
1863   */
1864  loader.isLowestEnabledRendition_ = function () {
1865    var media = loader.media();
1866
1867    if (!media || !media.attributes) {
1868      return false;
1869    }
1870
1871    var currentBandwidth = loader.media().attributes.BANDWIDTH || 0;
1872
1873    return !(loader.master.playlists.filter(function (element, index, array) {
1874      var enabled = typeof element.excludeUntil === 'undefined' || element.excludeUntil <= Date.now();
1875
1876      if (!enabled) {
1877        return false;
1878      }
1879
1880      var item = element.attributes.BANDWIDTH;
1881
1882      return item <= currentBandwidth;
1883    }).length > 1);
1884  };
1885
1886  /**
1887   * When called without any arguments, returns the currently
1888   * active media playlist. When called with a single argument,
1889   * triggers the playlist loader to asynchronously switch to the
1890   * specified media playlist. Calling this method while the
1891   * loader is in the HAVE_NOTHING causes an error to be emitted
1892   * but otherwise has no effect.
1893   *
1894   * @param {Object=} playlis tthe parsed media playlist
1895   * object to switch to
1896   * @return {Playlist} the current loaded media
1897   */
1898  loader.media = function (playlist) {
1899    var startingState = loader.state;
1900    var mediaChange = undefined;
1901
1902    // getter
1903    if (!playlist) {
1904      return loader.media_;
1905    }
1906
1907    // setter
1908    if (loader.state === 'HAVE_NOTHING') {
1909      throw new Error('Cannot switch media playlist from ' + loader.state);
1910    }
1911
1912    // find the playlist object if the target playlist has been
1913    // specified by URI
1914    if (typeof playlist === 'string') {
1915      if (!loader.master.playlists[playlist]) {
1916        throw new Error('Unknown playlist URI: ' + playlist);
1917      }
1918      playlist = loader.master.playlists[playlist];
1919    }
1920
1921    mediaChange = !loader.media_ || playlist.uri !== loader.media_.uri;
1922
1923    // switch to fully loaded playlists immediately
1924    if (loader.master.playlists[playlist.uri].endList) {
1925      // abort outstanding playlist requests
1926      if (request) {
1927        request.onreadystatechange = null;
1928        request.abort();
1929        request = null;
1930      }
1931      loader.state = 'HAVE_METADATA';
1932      loader.media_ = playlist;
1933
1934      // trigger media change if the active media has been updated
1935      if (mediaChange) {
1936        loader.trigger('mediachanging');
1937        loader.trigger('mediachange');
1938      }
1939      return;
1940    }
1941
1942    // switching to the active playlist is a no-op
1943    if (!mediaChange) {
1944      return;
1945    }
1946
1947    loader.state = 'SWITCHING_MEDIA';
1948
1949    // there is already an outstanding playlist request
1950    if (request) {
1951      if ((0, _resolveUrl2['default'])(loader.master.uri, playlist.uri) === request.url) {
1952        // requesting to switch to the same playlist multiple times
1953        // has no effect after the first
1954        return;
1955      }
1956      request.onreadystatechange = null;
1957      request.abort();
1958      request = null;
1959    }
1960
1961    // request the new playlist
1962    if (this.media_) {
1963      this.trigger('mediachanging');
1964    }
1965    request = this.hls_.xhr({
1966      uri: (0, _resolveUrl2['default'])(loader.master.uri, playlist.uri),
1967      withCredentials: withCredentials
1968    }, function (error, req) {
1969      // disposed
1970      if (!request) {
1971        return;
1972      }
1973
1974      if (error) {
1975        return playlistRequestError(request, playlist.uri, startingState);
1976      }
1977
1978      haveMetadata(req, playlist.uri);
1979
1980      // fire loadedmetadata the first time a media playlist is loaded
1981      if (startingState === 'HAVE_MASTER') {
1982        loader.trigger('loadedmetadata');
1983      } else {
1984        loader.trigger('mediachange');
1985      }
1986    });
1987  };
1988
1989  /**
1990   * set the bandwidth on an xhr to the bandwidth on the playlist
1991   */
1992  loader.setBandwidth = function (xhr) {
1993    loader.bandwidth = xhr.bandwidth;
1994  };
1995
1996  // In a live playlist, don't keep track of the expired time
1997  // until HLS tells us that "first play" has commenced
1998  loader.on('firstplay', function () {
1999    this.trackExpiredTime_ = true;
2000  });
2001
2002  // live playlist staleness timeout
2003  loader.on('mediaupdatetimeout', function () {
2004    if (loader.state !== 'HAVE_METADATA') {
2005      // only refresh the media playlist if no other activity is going on
2006      return;
2007    }
2008
2009    loader.state = 'HAVE_CURRENT_METADATA';
2010    request = this.hls_.xhr({
2011      uri: (0, _resolveUrl2['default'])(loader.master.uri, loader.media().uri),
2012      withCredentials: withCredentials
2013    }, function (error, req) {
2014      // disposed
2015      if (!request) {
2016        return;
2017      }
2018
2019      if (error) {
2020        return playlistRequestError(request, loader.media().uri);
2021      }
2022      haveMetadata(request, loader.media().uri);
2023    });
2024  });
2025
2026  /**
2027   * pause loading of the playlist
2028   */
2029  loader.pause = function () {
2030    loader.stopRequest();
2031    _globalWindow2['default'].clearTimeout(mediaUpdateTimeout);
2032  };
2033
2034  /**
2035   * start loading of the playlist
2036   */
2037  loader.load = function () {
2038    if (loader.started) {
2039      if (!loader.media().endList) {
2040        loader.trigger('mediaupdatetimeout');
2041      } else {
2042        loader.trigger('loadedplaylist');
2043      }
2044    } else {
2045      loader.start();
2046    }
2047  };
2048
2049  /**
2050   * start loading of the playlist
2051   */
2052  loader.start = function () {
2053    loader.started = true;
2054
2055    // request the specified URL
2056    request = _this.hls_.xhr({
2057      uri: srcUrl,
2058      withCredentials: withCredentials
2059    }, function (error, req) {
2060      var parser = undefined;
2061      var playlist = undefined;
2062      var i = undefined;
2063
2064      // disposed
2065      if (!request) {
2066        return;
2067      }
2068
2069      // clear the loader's request reference
2070      request = null;
2071
2072      if (error) {
2073        loader.error = {
2074          status: req.status,
2075          message: 'HLS playlist request error at URL: ' + srcUrl,
2076          responseText: req.responseText,
2077          // MEDIA_ERR_NETWORK
2078          code: 2
2079        };
2080        return loader.trigger('error');
2081      }
2082
2083      parser = new _m3u8Parser2['default'].Parser();
2084      parser.push(req.responseText);
2085      parser.end();
2086
2087      loader.state = 'HAVE_MASTER';
2088
2089      parser.manifest.uri = srcUrl;
2090
2091      // loaded a master playlist
2092      if (parser.manifest.playlists) {
2093        loader.master = parser.manifest;
2094
2095        // setup by-URI lookups and resolve media playlist URIs
2096        i = loader.master.playlists.length;
2097        while (i--) {
2098          playlist = loader.master.playlists[i];
2099          loader.master.playlists[playlist.uri] = playlist;
2100          playlist.resolvedUri = (0, _resolveUrl2['default'])(loader.master.uri, playlist.uri);
2101        }
2102
2103        // resolve any media group URIs
2104        for (var groupKey in loader.master.mediaGroups.AUDIO) {
2105          for (var labelKey in loader.master.mediaGroups.AUDIO[groupKey]) {
2106            var alternateAudio = loader.master.mediaGroups.AUDIO[groupKey][labelKey];
2107
2108            if (alternateAudio.uri) {
2109              alternateAudio.resolvedUri = (0, _resolveUrl2['default'])(loader.master.uri, alternateAudio.uri);
2110            }
2111          }
2112        }
2113
2114        loader.trigger('loadedplaylist');
2115        if (!request) {
2116          // no media playlist was specifically selected so start
2117          // from the first listed one
2118          loader.media(parser.manifest.playlists[0]);
2119        }
2120        return;
2121      }
2122
2123      // loaded a media playlist
2124      // infer a master playlist if none was previously requested
2125      loader.master = {
2126        mediaGroups: {
2127          'AUDIO': {},
2128          'VIDEO': {},
2129          'CLOSED-CAPTIONS': {},
2130          'SUBTITLES': {}
2131        },
2132        uri: _globalWindow2['default'].location.href,
2133        playlists: [{
2134          uri: srcUrl
2135        }]
2136      };
2137      loader.master.playlists[srcUrl] = loader.master.playlists[0];
2138      loader.master.playlists[0].resolvedUri = srcUrl;
2139      haveMetadata(req, srcUrl);
2140      return loader.trigger('loadedmetadata');
2141    });
2142  };
2143};
2144
2145PlaylistLoader.prototype = new _stream2['default']();
2146
2147/**
2148 * Update the PlaylistLoader state to reflect the changes in an
2149 * update to the current media playlist.
2150 *
2151 * @param {Object} update the updated media playlist object
2152 */
2153PlaylistLoader.prototype.updateMediaPlaylist_ = function (update) {
2154  var outdated = undefined;
2155  var i = undefined;
2156  var segment = undefined;
2157
2158  outdated = this.media_;
2159  this.media_ = this.master.playlists[update.uri];
2160
2161  if (!outdated) {
2162    return;
2163  }
2164
2165  // don't track expired time until this flag is truthy
2166  if (!this.trackExpiredTime_) {
2167    return;
2168  }
2169
2170  // if the update was the result of a rendition switch do not
2171  // attempt to calculate expired_ since media-sequences need not
2172  // correlate between renditions/variants
2173  if (update.uri !== outdated.uri) {
2174    return;
2175  }
2176
2177  // try using precise timing from first segment of the updated
2178  // playlist
2179  if (update.segments.length) {
2180    if (typeof update.segments[0].start !== 'undefined') {
2181      this.expired_ = update.segments[0].start;
2182      return;
2183    } else if (typeof update.segments[0].end !== 'undefined') {
2184      this.expired_ = update.segments[0].end - update.segments[0].duration;
2185      return;
2186    }
2187  }
2188
2189  // calculate expired by walking the outdated playlist
2190  i = update.mediaSequence - outdated.mediaSequence - 1;
2191
2192  for (; i >= 0; i--) {
2193    segment = outdated.segments[i];
2194
2195    if (!segment) {
2196      // we missed information on this segment completely between
2197      // playlist updates so we'll have to take an educated guess
2198      // once we begin buffering again, any error we introduce can
2199      // be corrected
2200      this.expired_ += outdated.targetDuration || 10;
2201      continue;
2202    }
2203
2204    if (typeof segment.end !== 'undefined') {
2205      this.expired_ = segment.end;
2206      return;
2207    }
2208    if (typeof segment.start !== 'undefined') {
2209      this.expired_ = segment.start + segment.duration;
2210      return;
2211    }
2212    this.expired_ += segment.duration;
2213  }
2214};
2215
2216exports['default'] = PlaylistLoader;
2217module.exports = exports['default'];
2218}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2219},{"./resolve-url":10,"./stream":13,"global/window":25,"m3u8-parser":62}],7:[function(require,module,exports){
2220(function (global){
2221/**
2222 * @file playlist.js
2223 *
2224 * Playlist related utilities.
2225 */
2226'use strict';
2227
2228Object.defineProperty(exports, '__esModule', {
2229  value: true
2230});
2231
2232function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2233
2234var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
2235
2236var _globalWindow = require('global/window');
2237
2238var _globalWindow2 = _interopRequireDefault(_globalWindow);
2239
2240var Playlist = {
2241  /**
2242   * The number of segments that are unsafe to start playback at in
2243   * a live stream. Changing this value can cause playback stalls.
2244   * See HTTP Live Streaming, "Playing the Media Playlist File"
2245   * https://tools.ietf.org/html/draft-pantos-http-live-streaming-18#section-6.3.3
2246   */
2247  UNSAFE_LIVE_SEGMENTS: 3
2248};
2249
2250/**
2251 * walk backward until we find a duration we can use
2252 * or return a failure
2253 *
2254 * @param {Playlist} playlist the playlist to walk through
2255 * @param {Number} endSequence the mediaSequence to stop walking on
2256 */
2257
2258var backwardDuration = function backwardDuration(playlist, endSequence) {
2259  var result = 0;
2260  var i = endSequence - playlist.mediaSequence;
2261  // if a start time is available for segment immediately following
2262  // the interval, use it
2263  var segment = playlist.segments[i];
2264
2265  // Walk backward until we find the latest segment with timeline
2266  // information that is earlier than endSequence
2267  if (segment) {
2268    if (typeof segment.start !== 'undefined') {
2269      return { result: segment.start, precise: true };
2270    }
2271    if (typeof segment.end !== 'undefined') {
2272      return {
2273        result: segment.end - segment.duration,
2274        precise: true
2275      };
2276    }
2277  }
2278  while (i--) {
2279    segment = playlist.segments[i];
2280    if (typeof segment.end !== 'undefined') {
2281      return { result: result + segment.end, precise: true };
2282    }
2283
2284    result += segment.duration;
2285
2286    if (typeof segment.start !== 'undefined') {
2287      return { result: result + segment.start, precise: true };
2288    }
2289  }
2290  return { result: result, precise: false };
2291};
2292
2293/**
2294 * walk forward until we find a duration we can use
2295 * or return a failure
2296 *
2297 * @param {Playlist} playlist the playlist to walk through
2298 * @param {Number} endSequence the mediaSequence to stop walking on
2299 */
2300var forwardDuration = function forwardDuration(playlist, endSequence) {
2301  var result = 0;
2302  var segment = undefined;
2303  var i = endSequence - playlist.mediaSequence;
2304  // Walk forward until we find the earliest segment with timeline
2305  // information
2306
2307  for (; i < playlist.segments.length; i++) {
2308    segment = playlist.segments[i];
2309    if (typeof segment.start !== 'undefined') {
2310      return {
2311        result: segment.start - result,
2312        precise: true
2313      };
2314    }
2315
2316    result += segment.duration;
2317
2318    if (typeof segment.end !== 'undefined') {
2319      return {
2320        result: segment.end - result,
2321        precise: true
2322      };
2323    }
2324  }
2325  // indicate we didn't find a useful duration estimate
2326  return { result: -1, precise: false };
2327};
2328
2329/**
2330  * Calculate the media duration from the segments associated with a
2331  * playlist. The duration of a subinterval of the available segments
2332  * may be calculated by specifying an end index.
2333  *
2334  * @param {Object} playlist a media playlist object
2335  * @param {Number=} endSequence an exclusive upper boundary
2336  * for the playlist.  Defaults to playlist length.
2337  * @param {Number} expired the amount of time that has dropped
2338  * off the front of the playlist in a live scenario
2339  * @return {Number} the duration between the first available segment
2340  * and end index.
2341  */
2342var intervalDuration = function intervalDuration(playlist, endSequence, expired) {
2343  var backward = undefined;
2344  var forward = undefined;
2345
2346  if (typeof endSequence === 'undefined') {
2347    endSequence = playlist.mediaSequence + playlist.segments.length;
2348  }
2349
2350  if (endSequence < playlist.mediaSequence) {
2351    return 0;
2352  }
2353
2354  // do a backward walk to estimate the duration
2355  backward = backwardDuration(playlist, endSequence);
2356  if (backward.precise) {
2357    // if we were able to base our duration estimate on timing
2358    // information provided directly from the Media Source, return
2359    // it
2360    return backward.result;
2361  }
2362
2363  // walk forward to see if a precise duration estimate can be made
2364  // that way
2365  forward = forwardDuration(playlist, endSequence);
2366  if (forward.precise) {
2367    // we found a segment that has been buffered and so it's
2368    // position is known precisely
2369    return forward.result;
2370  }
2371
2372  // return the less-precise, playlist-based duration estimate
2373  return backward.result + expired;
2374};
2375
2376/**
2377  * Calculates the duration of a playlist. If a start and end index
2378  * are specified, the duration will be for the subset of the media
2379  * timeline between those two indices. The total duration for live
2380  * playlists is always Infinity.
2381  *
2382  * @param {Object} playlist a media playlist object
2383  * @param {Number=} endSequence an exclusive upper
2384  * boundary for the playlist. Defaults to the playlist media
2385  * sequence number plus its length.
2386  * @param {Number=} expired the amount of time that has
2387  * dropped off the front of the playlist in a live scenario
2388  * @return {Number} the duration between the start index and end
2389  * index.
2390  */
2391var duration = function duration(playlist, endSequence, expired) {
2392  if (!playlist) {
2393    return 0;
2394  }
2395
2396  if (typeof expired !== 'number') {
2397    expired = 0;
2398  }
2399
2400  // if a slice of the total duration is not requested, use
2401  // playlist-level duration indicators when they're present
2402  if (typeof endSequence === 'undefined') {
2403    // if present, use the duration specified in the playlist
2404    if (playlist.totalDuration) {
2405      return playlist.totalDuration;
2406    }
2407
2408    // duration should be Infinity for live playlists
2409    if (!playlist.endList) {
2410      return _globalWindow2['default'].Infinity;
2411    }
2412  }
2413
2414  // calculate the total duration based on the segment durations
2415  return intervalDuration(playlist, endSequence, expired);
2416};
2417
2418exports.duration = duration;
2419/**
2420  * Calculates the interval of time that is currently seekable in a
2421  * playlist. The returned time ranges are relative to the earliest
2422  * moment in the specified playlist that is still available. A full
2423  * seekable implementation for live streams would need to offset
2424  * these values by the duration of content that has expired from the
2425  * stream.
2426  *
2427  * @param {Object} playlist a media playlist object
2428  * @param {Number=} expired the amount of time that has
2429  * dropped off the front of the playlist in a live scenario
2430  * @return {TimeRanges} the periods of time that are valid targets
2431  * for seeking
2432  */
2433var seekable = function seekable(playlist, expired) {
2434  var start = undefined;
2435  var end = undefined;
2436  var endSequence = undefined;
2437
2438  if (typeof expired !== 'number') {
2439    expired = 0;
2440  }
2441
2442  // without segments, there are no seekable ranges
2443  if (!playlist || !playlist.segments) {
2444    return (0, _videoJs.createTimeRange)();
2445  }
2446  // when the playlist is complete, the entire duration is seekable
2447  if (playlist.endList) {
2448    return (0, _videoJs.createTimeRange)(0, duration(playlist));
2449  }
2450
2451  // live playlists should not expose three segment durations worth
2452  // of content from the end of the playlist
2453  // https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-6.3.3
2454  start = intervalDuration(playlist, playlist.mediaSequence, expired);
2455  endSequence = Math.max(0, playlist.segments.length - Playlist.UNSAFE_LIVE_SEGMENTS);
2456  end = intervalDuration(playlist, playlist.mediaSequence + endSequence, expired);
2457  return (0, _videoJs.createTimeRange)(start, end);
2458};
2459
2460exports.seekable = seekable;
2461/**
2462 * Determine the index of the segment that contains a specified
2463 * playback position in a media playlist.
2464 *
2465 * @param {Object} playlist the media playlist to query
2466 * @param {Number} time The number of seconds since the earliest
2467 * possible position to determine the containing segment for
2468 * @param {Number=} expired the duration of content, in
2469 * seconds, that has been removed from this playlist because it
2470 * expired
2471 * @return {Number} The number of the media segment that contains
2472 * that time position.
2473 */
2474var getMediaIndexForTime_ = function getMediaIndexForTime_(playlist, time, expired) {
2475  var i = undefined;
2476  var segment = undefined;
2477  var originalTime = time;
2478  var numSegments = playlist.segments.length;
2479  var lastSegment = numSegments - 1;
2480  var startIndex = undefined;
2481  var endIndex = undefined;
2482  var knownStart = undefined;
2483  var knownEnd = undefined;
2484
2485  if (!playlist) {
2486    return 0;
2487  }
2488
2489  // when the requested position is earlier than the current set of
2490  // segments, return the earliest segment index
2491  if (time < 0) {
2492    return 0;
2493  }
2494
2495  if (time === 0 && !expired) {
2496    return 0;
2497  }
2498
2499  expired = expired || 0;
2500
2501  // find segments with known timing information that bound the
2502  // target time
2503  for (i = 0; i < numSegments; i++) {
2504    segment = playlist.segments[i];
2505    if (segment.end) {
2506      if (segment.end > time) {
2507        knownEnd = segment.end;
2508        endIndex = i;
2509        break;
2510      } else {
2511        knownStart = segment.end;
2512        startIndex = i + 1;
2513      }
2514    }
2515  }
2516
2517  // time was equal to or past the end of the last segment in the playlist
2518  if (startIndex === numSegments) {
2519    return numSegments;
2520  }
2521
2522  // use the bounds we just found and playlist information to
2523  // estimate the segment that contains the time we are looking for
2524  if (typeof startIndex !== 'undefined') {
2525    // We have a known-start point that is before our desired time so
2526    // walk from that point forwards
2527    time = time - knownStart;
2528    for (i = startIndex; i < (endIndex || numSegments); i++) {
2529      segment = playlist.segments[i];
2530      time -= segment.duration;
2531
2532      if (time < 0) {
2533        return i;
2534      }
2535    }
2536
2537    if (i >= endIndex) {
2538      // We haven't found a segment but we did hit a known end point
2539      // so fallback to interpolating between the segment index
2540      // based on the known span of the timeline we are dealing with
2541      // and the number of segments inside that span
2542      return startIndex + Math.floor((originalTime - knownStart) / (knownEnd - knownStart) * (endIndex - startIndex));
2543    }
2544
2545    // We _still_ haven't found a segment so load the last one
2546    return lastSegment;
2547  } else if (typeof endIndex !== 'undefined') {
2548    // We _only_ have a known-end point that is after our desired time so
2549    // walk from that point backwards
2550    time = knownEnd - time;
2551    for (i = endIndex; i >= 0; i--) {
2552      segment = playlist.segments[i];
2553      time -= segment.duration;
2554
2555      if (time < 0) {
2556        return i;
2557      }
2558    }
2559
2560    // We haven't found a segment so load the first one if time is zero
2561    if (time === 0) {
2562      return 0;
2563    }
2564    return -1;
2565  }
2566  // We known nothing so walk from the front of the playlist,
2567  // subtracting durations until we find a segment that contains
2568  // time and return it
2569  time = time - expired;
2570
2571  if (time < 0) {
2572    return -1;
2573  }
2574
2575  for (i = 0; i < numSegments; i++) {
2576    segment = playlist.segments[i];
2577    time -= segment.duration;
2578    if (time < 0) {
2579      return i;
2580    }
2581  }
2582  // We are out of possible candidates so load the last one...
2583  // The last one is the least likely to overlap a buffer and therefore
2584  // the one most likely to tell us something about the timeline
2585  return lastSegment;
2586};
2587
2588exports.getMediaIndexForTime_ = getMediaIndexForTime_;
2589Playlist.duration = duration;
2590Playlist.seekable = seekable;
2591Playlist.getMediaIndexForTime_ = getMediaIndexForTime_;
2592
2593// exports
2594exports['default'] = Playlist;
2595}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2596},{"global/window":25}],8:[function(require,module,exports){
2597(function (global){
2598/**
2599 * ranges
2600 *
2601 * Utilities for working with TimeRanges.
2602 *
2603 */
2604
2605'use strict';
2606
2607Object.defineProperty(exports, '__esModule', {
2608  value: true
2609});
2610
2611var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
2612
2613function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2614
2615var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
2616
2617var _videoJs2 = _interopRequireDefault(_videoJs);
2618
2619// Fudge factor to account for TimeRanges rounding
2620var TIME_FUDGE_FACTOR = 1 / 30;
2621
2622/**
2623 * Clamps a value to within a range
2624 * @param {Number} num - the value to clamp
2625 * @param {Number} start - the start of the range to clamp within, inclusive
2626 * @param {Number} end - the end of the range to clamp within, inclusive
2627 * @return {Number}
2628 */
2629var clamp = function clamp(num, _ref) {
2630  var _ref2 = _slicedToArray(_ref, 2);
2631
2632  var start = _ref2[0];
2633  var end = _ref2[1];
2634
2635  return Math.min(Math.max(start, num), end);
2636};
2637var filterRanges = function filterRanges(timeRanges, predicate) {
2638  var results = [];
2639  var i = undefined;
2640
2641  if (timeRanges && timeRanges.length) {
2642    // Search for ranges that match the predicate
2643    for (i = 0; i < timeRanges.length; i++) {
2644      if (predicate(timeRanges.start(i), timeRanges.end(i))) {
2645        results.push([timeRanges.start(i), timeRanges.end(i)]);
2646      }
2647    }
2648  }
2649
2650  return _videoJs2['default'].createTimeRanges(results);
2651};
2652
2653/**
2654 * Attempts to find the buffered TimeRange that contains the specified
2655 * time.
2656 * @param {TimeRanges} buffered - the TimeRanges object to query
2657 * @param {number} time  - the time to filter on.
2658 * @returns {TimeRanges} a new TimeRanges object
2659 */
2660var findRange = function findRange(buffered, time) {
2661  return filterRanges(buffered, function (start, end) {
2662    return start - TIME_FUDGE_FACTOR <= time && end + TIME_FUDGE_FACTOR >= time;
2663  });
2664};
2665
2666/**
2667 * Returns the TimeRanges that begin later than the specified time.
2668 * @param {TimeRanges} timeRanges - the TimeRanges object to query
2669 * @param {number} time - the time to filter on.
2670 * @returns {TimeRanges} a new TimeRanges object.
2671 */
2672var findNextRange = function findNextRange(timeRanges, time) {
2673  return filterRanges(timeRanges, function (start) {
2674    return start - TIME_FUDGE_FACTOR >= time;
2675  });
2676};
2677
2678/**
2679 * Returns gaps within a list of TimeRanges
2680 * @param {TimeRanges} buffered - the TimeRanges object
2681 * @return {TimeRanges} a TimeRanges object of gaps
2682 */
2683var findGaps = function findGaps(buffered) {
2684  if (buffered.length < 2) {
2685    return _videoJs2['default'].createTimeRanges();
2686  }
2687
2688  var ranges = [];
2689
2690  for (var i = 1; i < buffered.length; i++) {
2691    var start = buffered.end(i - 1);
2692    var end = buffered.start(i);
2693
2694    ranges.push([start, end]);
2695  }
2696
2697  return _videoJs2['default'].createTimeRanges(ranges);
2698};
2699
2700/**
2701 * Search for a likely end time for the segment that was just appened
2702 * based on the state of the `buffered` property before and after the
2703 * append. If we fin only one such uncommon end-point return it.
2704 * @param {TimeRanges} original - the buffered time ranges before the update
2705 * @param {TimeRanges} update - the buffered time ranges after the update
2706 * @returns {Number|null} the end time added between `original` and `update`,
2707 * or null if one cannot be unambiguously determined.
2708 */
2709var findSoleUncommonTimeRangesEnd = function findSoleUncommonTimeRangesEnd(original, update) {
2710  var i = undefined;
2711  var start = undefined;
2712  var end = undefined;
2713  var result = [];
2714  var edges = [];
2715
2716  // In order to qualify as a possible candidate, the end point must:
2717  //  1) Not have already existed in the `original` ranges
2718  //  2) Not result from the shrinking of a range that already existed
2719  //     in the `original` ranges
2720  //  3) Not be contained inside of a range that existed in `original`
2721  var overlapsCurrentEnd = function overlapsCurrentEnd(span) {
2722    return span[0] <= end && span[1] >= end;
2723  };
2724
2725  if (original) {
2726    // Save all the edges in the `original` TimeRanges object
2727    for (i = 0; i < original.length; i++) {
2728      start = original.start(i);
2729      end = original.end(i);
2730
2731      edges.push([start, end]);
2732    }
2733  }
2734
2735  if (update) {
2736    // Save any end-points in `update` that are not in the `original`
2737    // TimeRanges object
2738    for (i = 0; i < update.length; i++) {
2739      start = update.start(i);
2740      end = update.end(i);
2741
2742      if (edges.some(overlapsCurrentEnd)) {
2743        continue;
2744      }
2745
2746      // at this point it must be a unique non-shrinking end edge
2747      result.push(end);
2748    }
2749  }
2750
2751  // we err on the side of caution and return null if didn't find
2752  // exactly *one* differing end edge in the search above
2753  if (result.length !== 1) {
2754    return null;
2755  }
2756
2757  return result[0];
2758};
2759
2760/**
2761 * Calculate the intersection of two TimeRanges
2762 * @param {TimeRanges} bufferA
2763 * @param {TimeRanges} bufferB
2764 * @returns {TimeRanges} The interesection of `bufferA` with `bufferB`
2765 */
2766var bufferIntersection = function bufferIntersection(bufferA, bufferB) {
2767  var start = null;
2768  var end = null;
2769  var arity = 0;
2770  var extents = [];
2771  var ranges = [];
2772
2773  if (!bufferA || !bufferA.length || !bufferB || !bufferB.length) {
2774    return _videoJs2['default'].createTimeRange();
2775  }
2776
2777  // Handle the case where we have both buffers and create an
2778  // intersection of the two
2779  var count = bufferA.length;
2780
2781  // A) Gather up all start and end times
2782  while (count--) {
2783    extents.push({ time: bufferA.start(count), type: 'start' });
2784    extents.push({ time: bufferA.end(count), type: 'end' });
2785  }
2786  count = bufferB.length;
2787  while (count--) {
2788    extents.push({ time: bufferB.start(count), type: 'start' });
2789    extents.push({ time: bufferB.end(count), type: 'end' });
2790  }
2791  // B) Sort them by time
2792  extents.sort(function (a, b) {
2793    return a.time - b.time;
2794  });
2795
2796  // C) Go along one by one incrementing arity for start and decrementing
2797  //    arity for ends
2798  for (count = 0; count < extents.length; count++) {
2799    if (extents[count].type === 'start') {
2800      arity++;
2801
2802      // D) If arity is ever incremented to 2 we are entering an
2803      //    overlapping range
2804      if (arity === 2) {
2805        start = extents[count].time;
2806      }
2807    } else if (extents[count].type === 'end') {
2808      arity--;
2809
2810      // E) If arity is ever decremented to 1 we leaving an
2811      //    overlapping range
2812      if (arity === 1) {
2813        end = extents[count].time;
2814      }
2815    }
2816
2817    // F) Record overlapping ranges
2818    if (start !== null && end !== null) {
2819      ranges.push([start, end]);
2820      start = null;
2821      end = null;
2822    }
2823  }
2824
2825  return _videoJs2['default'].createTimeRanges(ranges);
2826};
2827
2828/**
2829 * Calculates the percentage of `segmentRange` that overlaps the
2830 * `buffered` time ranges.
2831 * @param {TimeRanges} segmentRange - the time range that the segment
2832 * covers adjusted according to currentTime
2833 * @param {TimeRanges} referenceRange - the original time range that the
2834 * segment covers
2835 * @param {Number} currentTime - time in seconds where the current playback
2836 * is at
2837 * @param {TimeRanges} buffered - the currently buffered time ranges
2838 * @returns {Number} percent of the segment currently buffered
2839 */
2840var calculateBufferedPercent = function calculateBufferedPercent(adjustedRange, referenceRange, currentTime, buffered) {
2841  var referenceDuration = referenceRange.end(0) - referenceRange.start(0);
2842  var adjustedDuration = adjustedRange.end(0) - adjustedRange.start(0);
2843  var bufferMissingFromAdjusted = referenceDuration - adjustedDuration;
2844  var adjustedIntersection = bufferIntersection(adjustedRange, buffered);
2845  var referenceIntersection = bufferIntersection(referenceRange, buffered);
2846  var adjustedOverlap = 0;
2847  var referenceOverlap = 0;
2848
2849  var count = adjustedIntersection.length;
2850
2851  while (count--) {
2852    adjustedOverlap += adjustedIntersection.end(count) - adjustedIntersection.start(count);
2853
2854    // If the current overlap segment starts at currentTime, then increase the
2855    // overlap duration so that it actually starts at the beginning of referenceRange
2856    // by including the difference between the two Range's durations
2857    // This is a work around for the way Flash has no buffer before currentTime
2858    if (adjustedIntersection.start(count) === currentTime) {
2859      adjustedOverlap += bufferMissingFromAdjusted;
2860    }
2861  }
2862
2863  count = referenceIntersection.length;
2864
2865  while (count--) {
2866    referenceOverlap += referenceIntersection.end(count) - referenceIntersection.start(count);
2867  }
2868
2869  // Use whichever value is larger for the percentage-buffered since that value
2870  // is likely more accurate because the only way
2871  return Math.max(adjustedOverlap, referenceOverlap) / referenceDuration * 100;
2872};
2873
2874/**
2875 * Return the amount of a range specified by the startOfSegment and segmentDuration
2876 * overlaps the current buffered content.
2877 *
2878 * @param {Number} startOfSegment - the time where the segment begins
2879 * @param {Number} segmentDuration - the duration of the segment in seconds
2880 * @param {Number} currentTime - time in seconds where the current playback
2881 * is at
2882 * @param {TimeRanges} buffered - the state of the buffer
2883 * @returns {Number} percentage of the segment's time range that is
2884 * already in `buffered`
2885 */
2886var getSegmentBufferedPercent = function getSegmentBufferedPercent(startOfSegment, segmentDuration, currentTime, buffered) {
2887  var endOfSegment = startOfSegment + segmentDuration;
2888
2889  // The entire time range of the segment
2890  var originalSegmentRange = _videoJs2['default'].createTimeRanges([[startOfSegment, endOfSegment]]);
2891
2892  // The adjusted segment time range that is setup such that it starts
2893  // no earlier than currentTime
2894  // Flash has no notion of a back-buffer so adjustedSegmentRange adjusts
2895  // for that and the function will still return 100% if a only half of a
2896  // segment is actually in the buffer as long as the currentTime is also
2897  // half-way through the segment
2898  var adjustedSegmentRange = _videoJs2['default'].createTimeRanges([[clamp(startOfSegment, [currentTime, endOfSegment]), endOfSegment]]);
2899
2900  // This condition happens when the currentTime is beyond the segment's
2901  // end time
2902  if (adjustedSegmentRange.start(0) === adjustedSegmentRange.end(0)) {
2903    return 0;
2904  }
2905
2906  var percent = calculateBufferedPercent(adjustedSegmentRange, originalSegmentRange, currentTime, buffered);
2907
2908  // If the segment is reported as having a zero duration, return 0%
2909  // since it is likely that we will need to fetch the segment
2910  if (isNaN(percent) || percent === Infinity || percent === -Infinity) {
2911    return 0;
2912  }
2913
2914  return percent;
2915};
2916
2917exports['default'] = {
2918  findRange: findRange,
2919  findNextRange: findNextRange,
2920  findGaps: findGaps,
2921  findSoleUncommonTimeRangesEnd: findSoleUncommonTimeRangesEnd,
2922  getSegmentBufferedPercent: getSegmentBufferedPercent,
2923  TIME_FUDGE_FACTOR: TIME_FUDGE_FACTOR
2924};
2925module.exports = exports['default'];
2926}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2927},{}],9:[function(require,module,exports){
2928/**
2929 * Enable/disable playlist function. It is intended to have the first two
2930 * arguments partially-applied in order to create the final per-playlist
2931 * function.
2932 *
2933 * @param {PlaylistLoader} playlist - The rendition or media-playlist
2934 * @param {Function} changePlaylistFn - A function to be called after a
2935 * playlist's enabled-state has been changed. Will NOT be called if a
2936 * playlist's enabled-state is unchanged
2937 * @param {Boolean=} enable - Value to set the playlist enabled-state to
2938 * or if undefined returns the current enabled-state for the playlist
2939 * @return {Boolean} The current enabled-state of the playlist
2940 */
2941'use strict';
2942
2943Object.defineProperty(exports, '__esModule', {
2944  value: true
2945});
2946
2947function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
2948
2949var enableFunction = function enableFunction(playlist, changePlaylistFn, enable) {
2950  var currentlyEnabled = typeof playlist.excludeUntil === 'undefined' || playlist.excludeUntil <= Date.now();
2951
2952  if (typeof enable === 'undefined') {
2953    return currentlyEnabled;
2954  }
2955
2956  if (enable !== currentlyEnabled) {
2957    if (enable) {
2958      delete playlist.excludeUntil;
2959    } else {
2960      playlist.excludeUntil = Infinity;
2961    }
2962
2963    // Ensure the outside world knows about our changes
2964    changePlaylistFn();
2965  }
2966
2967  return enable;
2968};
2969
2970/**
2971 * The representation object encapsulates the publicly visible information
2972 * in a media playlist along with a setter/getter-type function (enabled)
2973 * for changing the enabled-state of a particular playlist entry
2974 *
2975 * @class Representation
2976 */
2977
2978var Representation = function Representation(hlsHandler, playlist, id) {
2979  _classCallCheck(this, Representation);
2980
2981  // Get a reference to a bound version of fastQualityChange_
2982  var fastChangeFunction = hlsHandler.masterPlaylistController_.fastQualityChange_.bind(hlsHandler.masterPlaylistController_);
2983
2984  // Carefully descend into the playlist's attributes since most
2985  // properties are optional
2986  if (playlist.attributes) {
2987    var attributes = playlist.attributes;
2988
2989    if (attributes.RESOLUTION) {
2990      var resolution = attributes.RESOLUTION;
2991
2992      this.width = resolution.width;
2993      this.height = resolution.height;
2994    }
2995
2996    this.bandwidth = attributes.BANDWIDTH;
2997  }
2998
2999  // The id is simply the ordinality of the media playlist
3000  // within the master playlist
3001  this.id = id;
3002
3003  // Partially-apply the enableFunction to create a playlist-
3004  // specific variant
3005  this.enabled = enableFunction.bind(this, playlist, fastChangeFunction);
3006}
3007
3008/**
3009 * A mixin function that adds the `representations` api to an instance
3010 * of the HlsHandler class
3011 * @param {HlsHandler} hlsHandler - An instance of HlsHandler to add the
3012 * representation API into
3013 */
3014;
3015
3016var renditionSelectionMixin = function renditionSelectionMixin(hlsHandler) {
3017  var playlists = hlsHandler.playlists;
3018
3019  // Add a single API-specific function to the HlsHandler instance
3020  hlsHandler.representations = function () {
3021    return playlists.master.playlists.map(function (e, i) {
3022      return new Representation(hlsHandler, e, i);
3023    });
3024  };
3025};
3026
3027exports['default'] = renditionSelectionMixin;
3028module.exports = exports['default'];
3029},{}],10:[function(require,module,exports){
3030/**
3031 * @file resolve-url.js
3032 */
3033'use strict';
3034
3035Object.defineProperty(exports, '__esModule', {
3036  value: true
3037});
3038
3039function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3040
3041var _globalDocument = require('global/document');
3042
3043var _globalDocument2 = _interopRequireDefault(_globalDocument);
3044
3045/**
3046 * Constructs a new URI by interpreting a path relative to another
3047 * URI.
3048 *
3049 * @see http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
3050 * @param {String} basePath a relative or absolute URI
3051 * @param {String} path a path part to combine with the base
3052 * @return {String} a URI that is equivalent to composing `base`
3053 * with `path`
3054 */
3055var resolveUrl = function resolveUrl(basePath, path) {
3056  // use the base element to get the browser to handle URI resolution
3057  var oldBase = _globalDocument2['default'].querySelector('base');
3058  var docHead = _globalDocument2['default'].querySelector('head');
3059  var a = _globalDocument2['default'].createElement('a');
3060  var base = oldBase;
3061  var oldHref = undefined;
3062  var result = undefined;
3063
3064  // prep the document
3065  if (oldBase) {
3066    oldHref = oldBase.href;
3067  } else {
3068    base = docHead.appendChild(_globalDocument2['default'].createElement('base'));
3069  }
3070
3071  base.href = basePath;
3072  a.href = path;
3073  result = a.href;
3074
3075  // clean up
3076  if (oldBase) {
3077    oldBase.href = oldHref;
3078  } else {
3079    docHead.removeChild(base);
3080  }
3081  return result;
3082};
3083
3084exports['default'] = resolveUrl;
3085module.exports = exports['default'];
3086},{"global/document":24}],11:[function(require,module,exports){
3087(function (global){
3088/**
3089 * @file segment-loader.js
3090 */
3091'use strict';
3092
3093Object.defineProperty(exports, '__esModule', {
3094  value: true
3095});
3096
3097var _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; }; })();
3098
3099var _get = function get(_x2, _x3, _x4) { var _again = true; _function: while (_again) { var object = _x2, property = _x3, receiver = _x4; _again = false; 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 { _x2 = parent; _x3 = property; _x4 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
3100
3101function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3102
3103function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
3104
3105function _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, { c
3105onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
3106
3107var _ranges = require('./ranges');
3108
3109var _ranges2 = _interopRequireDefault(_ranges);
3110
3111var _playlist = require('./playlist');
3112
3113var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
3114
3115var _videoJs2 = _interopRequireDefault(_videoJs);
3116
3117var _sourceUpdater = require('./source-updater');
3118
3119var _sourceUpdater2 = _interopRequireDefault(_sourceUpdater);
3120
3121var _aesDecrypter = require('aes-decrypter');
3122
3123var _muxJsLibMp4Probe = require('mux.js/lib/mp4/probe');
3124
3125var _muxJsLibMp4Probe2 = _interopRequireDefault(_muxJsLibMp4Probe);
3126
3127var _config = require('./config');
3128
3129var _config2 = _interopRequireDefault(_config);
3130
3131var _globalWindow = require('global/window');
3132
3133var _globalWindow2 = _interopRequireDefault(_globalWindow);
3134
3135// in ms
3136var CHECK_BUFFER_DELAY = 500;
3137
3138/**
3139 * Updates segment with information about its end-point in time and, optionally,
3140 * the segment duration if we have enough information to determine a segment duration
3141 * accurately.
3142 *
3143 * @param {Object} playlist a media playlist object
3144 * @param {Number} segmentIndex the index of segment we last appended
3145 * @param {Number} segmentEnd the known of the segment referenced by segmentIndex
3146 */
3147var updateSegmentMetadata = function updateSegmentMetadata(playlist, segmentIndex, segmentEnd) {
3148  if (!playlist) {
3149    return false;
3150  }
3151
3152  var segment = playlist.segments[segmentIndex];
3153  var previousSegment = playlist.segments[segmentIndex - 1];
3154
3155  if (segmentEnd && segment) {
3156    segment.end = segmentEnd;
3157
3158    // fix up segment durations based on segment end data
3159    if (!previousSegment) {
3160      // first segment is always has a start time of 0 making its duration
3161      // equal to the segment end
3162      segment.duration = segment.end;
3163    } else if (previousSegment.end) {
3164      segment.duration = segment.end - previousSegment.end;
3165    }
3166    return true;
3167  }
3168  return false;
3169};
3170
3171/**
3172 * Determines if we should call endOfStream on the media source based
3173 * on the state of the buffer or if appened segment was the final
3174 * segment in the playlist.
3175 *
3176 * @param {Object} playlist a media playlist object
3177 * @param {Object} mediaSource the MediaSource object
3178 * @param {Number} segmentIndex the index of segment we last appended
3179 * @returns {Boolean} do we need to call endOfStream on the MediaSource
3180 */
3181var detectEndOfStream = function detectEndOfStream(playlist, mediaSource, segmentIndex) {
3182  if (!playlist) {
3183    return false;
3184  }
3185
3186  var segments = playlist.segments;
3187
3188  // determine a few boolean values to help make the branch below easier
3189  // to read
3190  var appendedLastSegment = segmentIndex === segments.length;
3191
3192  // if we've buffered to the end of the video, we need to call endOfStream
3193  // so that MediaSources can trigger the `ended` event when it runs out of
3194  // buffered data instead of waiting for me
3195  return playlist.endList && mediaSource.readyState === 'open' && appendedLastSegment;
3196};
3197
3198/**
3199 * Turns segment byterange into a string suitable for use in
3200 * HTTP Range requests
3201 */
3202var byterangeStr = function byterangeStr(byterange) {
3203  var byterangeStart = undefined;
3204  var byterangeEnd = undefined;
3205
3206  // `byterangeEnd` is one less than `offset + length` because the HTTP range
3207  // header uses inclusive ranges
3208  byterangeEnd = byterange.offset + byterange.length - 1;
3209  byterangeStart = byterange.offset;
3210  return 'bytes=' + byterangeStart + '-' + byterangeEnd;
3211};
3212
3213/**
3214 * Defines headers for use in the xhr request for a particular segment.
3215 */
3216var segmentXhrHeaders = function segmentXhrHeaders(segment) {
3217  var headers = {};
3218
3219  if ('byterange' in segment) {
3220    headers.Range = byterangeStr(segment.byterange);
3221  }
3222  return headers;
3223};
3224
3225/**
3226 * Returns a unique string identifier for a media initialization
3227 * segment.
3228 */
3229var initSegmentId = function initSegmentId(initSegment) {
3230  var byterange = initSegment.byterange || {
3231    length: Infinity,
3232    offset: 0
3233  };
3234
3235  return [byterange.length, byterange.offset, initSegment.resolvedUri].join(',');
3236};
3237
3238/**
3239 * An object that manages segment loading and appending.
3240 *
3241 * @class SegmentLoader
3242 * @param {Object} options required and optional options
3243 * @extends videojs.EventTarget
3244 */
3245
3246var SegmentLoader = (function (_videojs$EventTarget) {
3247  _inherits(SegmentLoader, _videojs$EventTarget);
3248
3249  function SegmentLoader(options) {
3250    _classCallCheck(this, SegmentLoader);
3251
3252    _get(Object.getPrototypeOf(SegmentLoader.prototype), 'constructor', this).call(this);
3253    var settings = undefined;
3254
3255    // check pre-conditions
3256    if (!options) {
3257      throw new TypeError('Initialization options are required');
3258    }
3259    if (typeof options.currentTime !== 'function') {
3260      throw new TypeError('No currentTime getter specified');
3261    }
3262    if (!options.mediaSource) {
3263      throw new TypeError('No MediaSource specified');
3264    }
3265    settings = _videoJs2['default'].mergeOptions(_videoJs2['default'].options.hls, options);
3266
3267    // public properties
3268    this.state = 'INIT';
3269    this.bandwidth = settings.bandwidth;
3270    this.roundTrip = NaN;
3271    this.resetStats_();
3272
3273    // private settings
3274    this.hasPlayed_ = settings.hasPlayed;
3275    this.currentTime_ = settings.currentTime;
3276    this.seekable_ = settings.seekable;
3277    this.seeking_ = settings.seeking;
3278    this.setCurrentTime_ = settings.setCurrentTime;
3279    this.mediaSource_ = settings.mediaSource;
3280
3281    this.hls_ = settings.hls;
3282
3283    // private instance variables
3284    this.checkBufferTimeout_ = null;
3285    this.error_ = void 0;
3286    this.expired_ = 0;
3287    this.timeCorrection_ = 0;
3288    this.currentTimeline_ = -1;
3289    this.zeroOffset_ = NaN;
3290    this.xhr_ = null;
3291    this.pendingSegment_ = null;
3292    this.mimeType_ = null;
3293    this.sourceUpdater_ = null;
3294    this.xhrOptions_ = null;
3295
3296    this.activeInitSegmentId_ = null;
3297    this.initSegments_ = {};
3298  }
3299
3300  /**
3301   * reset all of our media stats
3302   *
3303   * @private
3304   */
3305
3306  _createClass(SegmentLoader, [{
3307    key: 'resetStats_',
3308    value: function resetStats_() {
3309      this.mediaBytesTransferred = 0;
3310      this.mediaRequests = 0;
3311      this.mediaTransferDuration = 0;
3312    }
3313
3314    /**
3315     * dispose of the SegmentLoader and reset to the default state
3316     */
3317  }, {
3318    key: 'dispose',
3319    value: function dispose() {
3320      this.state = 'DISPOSED';
3321      this.abort_();
3322      if (this.sourceUpdater_) {
3323        this.sourceUpdater_.dispose();
3324      }
3325      this.resetStats_();
3326    }
3327
3328    /**
3329     * abort anything that is currently doing on with the SegmentLoader
3330     * and reset to a default state
3331     */
3332  }, {
3333    key: 'abort',
3334    value: function abort() {
3335      if (this.state !== 'WAITING') {
3336        return;
3337      }
3338
3339      this.abort_();
3340
3341      // don't wait for buffer check timeouts to begin fetching the
3342      // next segment
3343      if (!this.paused()) {
3344        this.state = 'READY';
3345        this.fillBuffer_();
3346      }
3347    }
3348
3349    /**
3350     * set an error on the segment loader and null out any pending segements
3351     *
3352     * @param {Error} error the error to set on the SegmentLoader
3353     * @return {Error} the error that was set or that is currently set
3354     */
3355  }, {
3356    key: 'error',
3357    value: function error(_error) {
3358      if (typeof _error !== 'undefined') {
3359        this.error_ = _error;
3360      }
3361
3362      this.pendingSegment_ = null;
3363      return this.error_;
3364    }
3365
3366    /**
3367     * load a playlist and start to fill the buffer
3368     */
3369  }, {
3370    key: 'load',
3371    value: function load() {
3372      // un-pause
3373      this.monitorBuffer_();
3374
3375      // if we don't have a playlist yet, keep waiting for one to be
3376      // specified
3377      if (!this.playlist_) {
3378        return;
3379      }
3380
3381      // if all the configuration is ready, initialize and begin loading
3382      if (this.state === 'INIT' && this.mimeType_) {
3383        return this.init_();
3384      }
3385
3386      // if we're in the middle of processing a segment already, don't
3387      // kick off an additional segment request
3388      if (!this.sourceUpdater_ || this.state !== 'READY' && this.state !== 'INIT') {
3389        return;
3390      }
3391
3392      this.state = 'READY';
3393      this.fillBuffer_();
3394    }
3395
3396    /**
3397     * set a playlist on the segment loader
3398     *
3399     * @param {PlaylistLoader} media the playlist to set on the segment loader
3400     */
3401  }, {
3402    key: 'playlist',
3403    value: function playlist(media) {
3404      var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
3405
3406      if (!media) {
3407        return;
3408      }
3409
3410      this.playlist_ = media;
3411      this.xhrOptions_ = options;
3412
3413      // if we were unpaused but waiting for a playlist, start
3414      // buffering now
3415      if (this.mimeType_ && this.state === 'INIT' && !this.paused()) {
3416        return this.init_();
3417      }
3418    }
3419
3420    /**
3421     * Prevent the loader from fetching additional segments. If there
3422     * is a segment request outstanding, it will finish processing
3423     * before the loader halts. A segment loader can be unpaused by
3424     * calling load().
3425     */
3426  }, {
3427    key: 'pause',
3428    value: function pause() {
3429      if (this.checkBufferTimeout_) {
3430        _globalWindow2['default'].clearTimeout(this.checkBufferTimeout_);
3431
3432        this.checkBufferTimeout_ = null;
3433      }
3434    }
3435
3436    /**
3437     * Returns whether the segment loader is fetching additional
3438     * segments when given the opportunity. This property can be
3439     * modified through calls to pause() and load().
3440     */
3441  }, {
3442    key: 'paused',
3443    value: function paused() {
3444      return this.checkBufferTimeout_ === null;
3445    }
3446
3447    /**
3448     * setter for expired time on the SegmentLoader
3449     *
3450     * @param {Number} expired the exired time to set
3451     */
3452  }, {
3453    key: 'expired',
3454    value: function expired(_expired) {
3455      this.expired_ = _expired;
3456    }
3457
3458    /**
3459     * create/set the following mimetype on the SourceBuffer through a
3460     * SourceUpdater
3461     *
3462     * @param {String} mimeType the mime type string to use
3463     */
3464  }, {
3465    key: 'mimeType',
3466    value: function mimeType(_mimeType) {
3467      if (this.mimeType_) {
3468        return;
3469      }
3470
3471      this.mimeType_ = _mimeType;
3472      // if we were unpaused but waiting for a sourceUpdater, start
3473      // buffering now
3474      if (this.playlist_ && this.state === 'INIT' && !this.paused()) {
3475        this.init_();
3476      }
3477    }
3478
3479    /**
3480     * As long as the SegmentLoader is in the READY state, periodically
3481     * invoke fillBuffer_().
3482     *
3483     * @private
3484     */
3485  }, {
3486    key: 'monitorBuffer_',
3487    value: function monitorBuffer_() {
3488      if (this.state === 'READY') {
3489        this.fillBuffer_();
3490      }
3491
3492      if (this.checkBufferTimeout_) {
3493        _globalWindow2['default'].clearTimeout(this.checkBufferTimeout_);
3494      }
3495
3496      this.checkBufferTimeout_ = _globalWindow2['default'].setTimeout(this.monitorBuffer_.bind(this), CHECK_BUFFER_DELAY);
3497    }
3498
3499    /**
3500     * Determines what segment request should be made, given current
3501     * playback state.
3502     *
3503     * @param {TimeRanges} buffered - the state of the buffer
3504     * @param {Object} playlist - the playlist object to fetch segments from
3505     * @param {Number} currentTime - the playback position in seconds
3506     * @param {Boolean} hasPlayed - if the player has played before
3507     * @param {Number} expired - the seconds expired off the playlist
3508     * @param {Number} timeCorrection - correction value to add to current time when
3509     *  when determining media index to use
3510     * @returns {Object} a segment info object that describes the
3511     * request that should be made or null if no request is necessary
3512     */
3513  }, {
3514    key: 'checkBuffer_',
3515    value: function checkBuffer_(buffered, playlist, currentTime, hasPlayed, expired, timeCorrection) {
3516      var currentBuffered = _ranges2['default'].findRange(buffered, currentTime);
3517
3518      // There are times when MSE reports the first segment as starting a
3519      // little after 0-time so add a fudge factor to try and fix those cases
3520      // or we end up fetching the same first segment over and over
3521      if (currentBuffered.length === 0 && currentTime === 0) {
3522        currentBuffered = _ranges2['default'].findRange(buffered, currentTime + _ranges2['default'].TIME_FUDGE_FACTOR);
3523      }
3524
3525      var bufferedTime = undefined;
3526      var currentBufferedEnd = undefined;
3527      var mediaIndex = undefined;
3528
3529      if (!playlist.segments.length) {
3530        return null;
3531      }
3532
3533      if (currentBuffered.length === 0) {
3534        // find the segment containing currentTime
3535        mediaIndex = (0, _playlist.getMediaIndexForTime_)(playlist, currentTime + timeCorrection, expired);
3536      } else {
3537        // find the segment adjacent to the end of the current
3538        // buffered region
3539        currentBufferedEnd = currentBuffered.end(0);
3540        bufferedTime = Math.max(0, currentBufferedEnd - currentTime);
3541
3542        // if the video has not yet played only, and we already have
3543        // one segment downloaded do nothing
3544        if (!hasPlayed && bufferedTime >= 1) {
3545          return null;
3546        }
3547
3548        // if there is plenty of content buffered, and the video has
3549        // been played before relax for awhile
3550        if (hasPlayed && bufferedTime >= _config2['default'].GOAL_BUFFER_LENGTH) {
3551          return null;
3552        }
3553        mediaIndex = (0, _playlist.getMediaIndexForTime_)(playlist, currentBufferedEnd + timeCorrection, expired);
3554      }
3555
3556      return mediaIndex;
3557    }
3558
3559    /**
3560     * abort all pending xhr requests and null any pending segements
3561     *
3562     * @private
3563     */
3564  }, {
3565    key: 'abort_',
3566    value: function abort_() {
3567      if (this.xhr_) {
3568        this.xhr_.abort();
3569      }
3570
3571      // clear out the segment being processed
3572      this.pendingSegment_ = null;
3573    }
3574
3575    /**
3576     * Once all the starting parameters have been specified, begin
3577     * operation. This method should only be invoked from the INIT
3578     * state.
3579     */
3580  }, {
3581    key: 'init_',
3582    value: function init_() {
3583      this.state = 'READY';
3584      this.sourceUpdater_ = new _sourceUpdater2['default'](this.mediaSource_, this.mimeType_);
3585      this.clearBuffer();
3586      return this.fillBuffer_();
3587    }
3588
3589    /**
3590     * fill the buffer with segements unless the
3591     * sourceBuffers are currently updating
3592     *
3593     * @private
3594     */
3595  }, {
3596    key: 'fillBuffer_',
3597    value: function fillBuffer_() {
3598      if (this.sourceUpdater_.updating()) {
3599        return;
3600      }
3601
3602      var buffered = this.sourceUpdater_.buffered();
3603      var playlist = this.playlist_;
3604      var currentTime = this.currentTime_();
3605      var hasPlayed = this.hasPlayed_();
3606      var expired = this.expired_;
3607      var timeCorrection = this.timeCorrection_;
3608
3609      // see if we need to begin loading immediately
3610      var requestIndex = this.checkBuffer_(buffered, playlist, currentTime, hasPlayed, expired, timeCorrection);
3611
3612      if (requestIndex === null) {
3613        return;
3614      }
3615
3616      var isEndOfStream = detectEndOfStream(playlist, this.mediaSource_, requestIndex);
3617
3618      if (isEndOfStream) {
3619        this.mediaSource_.endOfStream();
3620        return;
3621      }
3622
3623      if (requestIndex === playlist.segments.length - 1 && this.mediaSource_.readyState === 'ended' && !this.seeking_()) {
3624        return;
3625      }
3626
3627      if (requestIndex < 0 || requestIndex >= playlist.segments.length) {
3628        return;
3629      }
3630
3631      var segment = this.playlist_.segments[requestIndex];
3632
3633      var request = {
3634        // resolve the segment URL relative to the playlist
3635        uri: segment.resolvedUri,
3636        // the segment's mediaIndex at the time it was requested
3637        mediaIndex: requestIndex,
3638        // the segment's playlist
3639        playlist: playlist,
3640        // unencrypted bytes of the segment
3641        bytes: null,
3642        // when a key is defined for this segment, the encrypted bytes
3643        encryptedBytes: null,
3644        // the state of the buffer before a segment is appended will be
3645        // stored here so that the actual segment duration can be
3646        // determined after it has been appended
3647        buffered: null,
3648        // The target timestampOffset for this segment when we append it
3649        // to the source buffer
3650        timestampOffset: NaN,
3651        // The timeline that the segment is in
3652        timeline: segment.timeline,
3653        // The expected duration of the segment in seconds
3654        duration: segment.duration
3655      };
3656
3657      var startOfSegment = (0, _playlist.duration)(playlist, playlist.mediaSequence + request.mediaIndex, expired);
3658
3659      //   (we are crossing a discontinuity somehow)
3660      // - The "timestampOffset" for the start of this segment is less than
3661      //   the currently set timestampOffset
3662      request.timestampOffset = this.sourceUpdater_.timestampOffset();
3663      if (segment.timeline !== this.currentTimeline_ || startOfSegment < this.sourceUpdater_.timestampOffset()) {
3664        request.timestampOffset = startOfSegment;
3665      }
3666
3667      // Sanity check the segment-index determining logic by calcuating the
3668      // percentage of the chosen segment that is buffered. If more than 90%
3669      // of the segment is buffered then fetching it will likely not help in
3670      // any way
3671      var percentBuffered = _ranges2['default'].getSegmentBufferedPercent(startOfSegment, segment.duration, currentTime, buffered);
3672
3673      if (percentBuffered >= 90) {
3674        // Increment the timeCorrection_ variable to push the fetcher forward
3675        // in time and hopefully skip any gaps or flaws in our understanding
3676        // of the media
3677        var correctionApplied = this.incrementTimeCorrection_(playlist.targetDuration / 2, 1);
3678
3679        if (correctionApplied && !this.paused()) {
3680          this.fillBuffer_();
3681        }
3682
3683        return;
3684      }
3685
3686      this.loadSegment_(request);
3687    }
3688
3689    /**
3690     * trim the back buffer so we only remove content
3691     * on segment boundaries
3692     *
3693     * @private
3694     *
3695     * @param {Object} segmentInfo - the current segment
3696     * @returns {Number}
3696 removeToTime - the end point in time, in seconds
3697     * that the the buffer should be trimmed.
3698     */
3699  }, {
3700    key: 'trimBuffer_',
3701    value: function trimBuffer_(segmentInfo) {
3702      var seekable = this.seekable_();
3703      var currentTime = this.currentTime_();
3704      var removeToTime = 0;
3705
3706      // Chrome has a hard limit of 150mb of
3707      // buffer and a very conservative "garbage collector"
3708      // We manually clear out the old buffer to ensure
3709      // we don't trigger the QuotaExceeded error
3710      // on the source buffer during subsequent appends
3711
3712      // If we have a seekable range use that as the limit for what can be removed safely
3713      // otherwise remove anything older than 1 minute before the current play head
3714      if (seekable.length && seekable.start(0) > 0 && seekable.start(0) < currentTime) {
3715        removeToTime = seekable.start(0);
3716      } else {
3717        removeToTime = currentTime - 60;
3718      }
3719
3720      // If we are going to remove time from the front of the buffer, make
3721      // sure we aren't discarding a partial segment to avoid throwing
3722      // PLAYER_ERR_TIMEOUT while trying to read a partially discarded segment
3723      for (var i = 0; i <= segmentInfo.playlist.segments.length; i++) {
3724        // Loop through the segments and calculate the duration to compare
3725        // against the removeToTime
3726        var removeDuration = (0, _playlist.duration)(segmentInfo.playlist, segmentInfo.playlist.mediaSequence + i, this.expired_);
3727
3728        // If we are close to next segment begining, remove to end of previous
3729        // segment instead
3730        var previousDuration = (0, _playlist.duration)(segmentInfo.playlist, segmentInfo.playlist.mediaSequence + (i - 1), this.expired_);
3731
3732        if (removeDuration >= removeToTime) {
3733          removeToTime = previousDuration;
3734          break;
3735        }
3736      }
3737      return removeToTime;
3738    }
3739
3740    /**
3741     * load a specific segment from a request into the buffer
3742     *
3743     * @private
3744     */
3745  }, {
3746    key: 'loadSegment_',
3747    value: function loadSegment_(segmentInfo) {
3748      var segment = undefined;
3749      var keyXhr = undefined;
3750      var initSegmentXhr = undefined;
3751      var segmentXhr = undefined;
3752      var removeToTime = 0;
3753
3754      removeToTime = this.trimBuffer_(segmentInfo);
3755
3756      if (removeToTime > 0) {
3757        this.sourceUpdater_.remove(0, removeToTime);
3758      }
3759
3760      segment = segmentInfo.playlist.segments[segmentInfo.mediaIndex];
3761
3762      // optionally, request the decryption key
3763      if (segment.key) {
3764        var keyRequestOptions = _videoJs2['default'].mergeOptions(this.xhrOptions_, {
3765          uri: segment.key.resolvedUri,
3766          responseType: 'arraybuffer'
3767        });
3768
3769        keyXhr = this.hls_.xhr(keyRequestOptions, this.handleResponse_.bind(this));
3770      }
3771
3772      // optionally, request the associated media init segment
3773      if (segment.map && !this.initSegments_[initSegmentId(segment.map)]) {
3774        var initSegmentOptions = _videoJs2['default'].mergeOptions(this.xhrOptions_, {
3775          uri: segment.map.resolvedUri,
3776          responseType: 'arraybuffer',
3777          headers: segmentXhrHeaders(segment.map)
3778        });
3779
3780        initSegmentXhr = this.hls_.xhr(initSegmentOptions, this.handleResponse_.bind(this));
3781      }
3782      this.pendingSegment_ = segmentInfo;
3783
3784      var segmentRequestOptions = _videoJs2['default'].mergeOptions(this.xhrOptions_, {
3785        uri: segmentInfo.uri,
3786        responseType: 'arraybuffer',
3787        headers: segmentXhrHeaders(segment)
3788      });
3789
3790      segmentXhr = this.hls_.xhr(segmentRequestOptions, this.handleResponse_.bind(this));
3791
3792      this.xhr_ = {
3793        keyXhr: keyXhr,
3794        initSegmentXhr: initSegmentXhr,
3795        segmentXhr: segmentXhr,
3796        abort: function abort() {
3797          if (this.segmentXhr) {
3798            // Prevent error handler from running.
3799            this.segmentXhr.onreadystatechange = null;
3800            this.segmentXhr.abort();
3801            this.segmentXhr = null;
3802          }
3803          if (this.initSegmentXhr) {
3804            // Prevent error handler from running.
3805            this.initSegmentXhr.onreadystatechange = null;
3806            this.initSegmentXhr.abort();
3807            this.initSegmentXhr = null;
3808          }
3809          if (this.keyXhr) {
3810            // Prevent error handler from running.
3811            this.keyXhr.onreadystatechange = null;
3812            this.keyXhr.abort();
3813            this.keyXhr = null;
3814          }
3815        }
3816      };
3817
3818      this.state = 'WAITING';
3819    }
3820
3821    /**
3822     * triggered when a segment response is received
3823     *
3824     * @private
3825     */
3826  }, {
3827    key: 'handleResponse_',
3828    value: function handleResponse_(error, request) {
3829      var segmentInfo = undefined;
3830      var segment = undefined;
3831      var keyXhrRequest = undefined;
3832      var view = undefined;
3833
3834      // timeout of previously aborted request
3835      if (!this.xhr_ || request !== this.xhr_.segmentXhr && request !== this.xhr_.keyXhr && request !== this.xhr_.initSegmentXhr) {
3836        return;
3837      }
3838
3839      segmentInfo = this.pendingSegment_;
3840      segment = segmentInfo.playlist.segments[segmentInfo.mediaIndex];
3841
3842      // if a request times out, reset bandwidth tracking
3843      if (request.timedout) {
3844        this.abort_();
3845        this.bandwidth = 1;
3846        this.roundTrip = NaN;
3847        this.state = 'READY';
3848        return this.trigger('progress');
3849      }
3850
3851      // trigger an event for other errors
3852      if (!request.aborted && error) {
3853        // abort will clear xhr_
3854        keyXhrRequest = this.xhr_.keyXhr;
3855        this.abort_();
3856        this.error({
3857          status: request.status,
3858          message: request === keyXhrRequest ? 'HLS key request error at URL: ' + segment.key.uri : 'HLS segment request error at URL: ' + segmentInfo.uri,
3859          code: 2,
3860          xhr: request
3861        });
3862        this.state = 'READY';
3863        this.pause();
3864        return this.trigger('error');
3865      }
3866
3867      // stop processing if the request was aborted
3868      if (!request.response) {
3869        this.abort_();
3870        return;
3871      }
3872
3873      if (request === this.xhr_.segmentXhr) {
3874        // the segment request is no longer outstanding
3875        this.xhr_.segmentXhr = null;
3876
3877        // calculate the download bandwidth based on segment request
3878        this.roundTrip = request.roundTripTime;
3879        this.bandwidth = request.bandwidth;
3880        this.mediaBytesTransferred += request.bytesReceived || 0;
3881        this.mediaRequests += 1;
3882        this.mediaTransferDuration += request.roundTripTime || 0;
3883
3884        if (segment.key) {
3885          segmentInfo.encryptedBytes = new Uint8Array(request.response);
3886        } else {
3887          segmentInfo.bytes = new Uint8Array(request.response);
3888        }
3889      }
3890
3891      if (request === this.xhr_.keyXhr) {
3892        keyXhrRequest = this.xhr_.segmentXhr;
3893        // the key request is no longer outstanding
3894        this.xhr_.keyXhr = null;
3895
3896        if (request.response.byteLength !== 16) {
3897          this.abort_();
3898          this.error({
3899            status: request.status,
3900            message: 'Invalid HLS key at URL: ' + segment.key.uri,
3901            code: 2,
3902            xhr: request
3903          });
3904          this.state = 'READY';
3905          this.pause();
3906          return this.trigger('error');
3907        }
3908
3909        view = new DataView(request.response);
3910        segment.key.bytes = new Uint32Array([view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12)]);
3911
3912        // if the media sequence is greater than 2^32, the IV will be incorrect
3913        // assuming 10s segments, that would be about 1300 years
3914        segment.key.iv = segment.key.iv || new Uint32Array([0, 0, 0, segmentInfo.mediaIndex + segmentInfo.playlist.mediaSequence]);
3915      }
3916
3917      if (request === this.xhr_.initSegmentXhr) {
3918        // the init segment request is no longer outstanding
3919        this.xhr_.initSegmentXhr = null;
3920        segment.map.bytes = new Uint8Array(request.response);
3921        this.initSegments_[initSegmentId(segment.map)] = segment.map;
3922      }
3923
3924      if (!this.xhr_.segmentXhr && !this.xhr_.keyXhr && !this.xhr_.initSegmentXhr) {
3925        this.xhr_ = null;
3926        this.processResponse_();
3927      }
3928    }
3929
3930    /**
3931     * clear anything that is currently in the buffer and throw it away
3932     */
3933  }, {
3934    key: 'clearBuffer',
3935    value: function clearBuffer() {
3936      if (this.sourceUpdater_ && this.sourceUpdater_.buffered().length) {
3937        this.sourceUpdater_.remove(0, Infinity);
3938      }
3939    }
3940
3941    /**
3942     * Decrypt the segment that is being loaded if necessary
3943     *
3944     * @private
3945     */
3946  }, {
3947    key: 'processResponse_',
3948    value: function processResponse_() {
3949      var segmentInfo = undefined;
3950      var segment = undefined;
3951
3952      this.state = 'DECRYPTING';
3953
3954      segmentInfo = this.pendingSegment_;
3955      segment = segmentInfo.playlist.segments[segmentInfo.mediaIndex];
3956
3957      // some videos don't start from presentation time zero
3958      // if that is the case, set the timestamp offset on the first
3959      // segment to adjust them so that it is not necessary to seek
3960      // before playback can begin
3961      if (segment.map && isNaN(this.zeroOffset_)) {
3962        var timescales = _muxJsLibMp4Probe2['default'].timescale(segment.map.bytes);
3963        var startTime = _muxJsLibMp4Probe2['default'].startTime(timescales, segmentInfo.bytes);
3964
3965        this.zeroOffset_ = startTime;
3966        segmentInfo.timestampOffset -= startTime;
3967      }
3968
3969      if (segment.key) {
3970        // this is an encrypted segment
3971        // incrementally decrypt the segment
3972        /* eslint-disable no-new, handle-callback-err */
3973        new _aesDecrypter.Decrypter(segmentInfo.encryptedBytes, segment.key.bytes, segment.key.iv, (function (err, bytes) {
3974          // err always null
3975          segmentInfo.bytes = bytes;
3976          this.handleSegment_();
3977        }).bind(this));
3978        /* eslint-enable */
3979      } else {
3980          this.handleSegment_();
3981        }
3982    }
3983
3984    /**
3985     * append a decrypted segement to the SourceBuffer through a SourceUpdater
3986     *
3987     * @private
3988     */
3989  }, {
3990    key: 'handleSegment_',
3991    value: function handleSegment_() {
3992      var _this = this;
3993
3994      var segmentInfo = undefined;
3995      var segment = undefined;
3996
3997      this.state = 'APPENDING';
3998      segmentInfo = this.pendingSegment_;
3999      segmentInfo.buffered = this.sourceUpdater_.buffered();
4000      segment = segmentInfo.playlist.segments[segmentInfo.mediaIndex];
4001      this.currentTimeline_ = segmentInfo.timeline;
4002
4003      if (segmentInfo.timestampOffset !== this.sourceUpdater_.timestampOffset()) {
4004        this.sourceUpdater_.timestampOffset(segmentInfo.timestampOffset);
4005      }
4006
4007      // if the media initialization segment is changing, append it
4008      // before the content segment
4009      if (segment.map) {
4010        (function () {
4011          var initId = initSegmentId(segment.map);
4012
4013          if (!_this.activeInitSegmentId_ || _this.activeInitSegmentId_ !== initId) {
4014            var initSegment = _this.initSegments_[initId];
4015
4016            _this.sourceUpdater_.appendBuffer(initSegment.bytes, function () {
4017              _this.activeInitSegmentId_ = initId;
4018            });
4019          }
4020        })();
4021      }
4022
4023      this.sourceUpdater_.appendBuffer(segmentInfo.bytes, this.handleUpdateEnd_.bind(this));
4024    }
4025
4026    /**
4027     * callback to run when appendBuffer is finished. detects if we are
4028     * in a good state to do things with the data we got, or if we need
4029     * to wait for more
4030     *
4031     * @private
4032     */
4033  }, {
4034    key: 'handleUpdateEnd_',
4035    value: function handleUpdateEnd_() {
4036      var segmentInfo = this.pendingSegment_;
4037      var currentTime = this.currentTime_();
4038
4039      this.pendingSegment_ = null;
4040
4041      // add segment metadata if it we have gained information during the
4042      // last append
4043      var timelineUpdated = this.updateTimeline_(segmentInfo);
4044
4045      this.trigger('progress');
4046
4047      var currentMediaIndex = segmentInfo.mediaIndex;
4048
4049      currentMediaIndex += segmentInfo.playlist.mediaSequence - this.playlist_.mediaSequence;
4050
4051      var currentBuffered = _ranges2['default'].findRange(this.sourceUpdater_.buffered(), currentTime);
4052
4053      // any time an update finishes and the last segment is in the
4054      // buffer, end the stream. this ensures the "ended" event will
4055      // fire if playback reaches that point.
4056      var isEndOfStream = detectEndOfStream(segmentInfo.playlist, this.mediaSource_, currentMediaIndex + 1);
4057
4058      if (isEndOfStream) {
4059        this.mediaSource_.endOfStream();
4060      }
4061
4062      // when seeking to the beginning of the seekable range, it's
4063      // possible that imprecise timing information may cause the seek to
4064      // end up earlier than the start of the range
4065      // in that case, seek again
4066      var seekable = this.seekable_();
4067      var next = _ranges2['default'].findNextRange(this.sourceUpdater_.buffered(), currentTime);
4068
4069      if (this.seeking_() && currentBuffered.length === 0) {
4070        if (seekable.length && currentTime < seekable.start(0)) {
4071
4072          if (next.length) {
4073            _videoJs2['default'].log('tried seeking to', currentTime, 'but that was too early, retrying at', next.start(0));
4074            this.setCurrentTime_(next.start(0) + _ranges2['default'].TIME_FUDGE_FACTOR);
4075          }
4076        }
4077      }
4078
4079      this.state = 'READY';
4080
4081      if (timelineUpdated) {
4082        this.timeCorrection_ = 0;
4083        if (!this.paused()) {
4084          this.fillBuffer_();
4085        }
4086        return;
4087      }
4088
4089      // the last segment append must have been entirely in the
4090      // already buffered time ranges. adjust the timeCorrection
4091      // offset to fetch forward until we find a segment that adds
4092      // to the buffered time ranges and improves subsequent media
4093      // index calculations.
4094      var correctionApplied = this.incrementTimeCorrection_(segmentInfo.duration, 4);
4095
4096      if (correctionApplied && !this.paused()) {
4097        this.fillBuffer_();
4098      }
4099    }
4100
4101    /**
4102     * annotate the segment with any start and end time information
4103     * added by the media processing
4104     *
4105     * @private
4106     * @param {Object} segmentInfo annotate a segment with time info
4107     */
4108  }, {
4109    key: 'updateTimeline_',
4110    value: function updateTimeline_(segmentInfo) {
4111      var segment = undefined;
4112      var segmentEnd = undefined;
4113      var timelineUpdated = false;
4114      var playlist = segmentInfo.playlist;
4115      var currentMediaIndex = segmentInfo.mediaIndex;
4116
4117      currentMediaIndex += playlist.mediaSequence - this.playlist_.mediaSequence;
4118      segment = playlist.segments[currentMediaIndex];
4119
4120      // Update segment meta-data (duration and end-point) based on timeline
4121      if (segment && segmentInfo && segmentInfo.playlist.uri === this.playlist_.uri) {
4122        segmentEnd = _ranges2['default'].findSoleUncommonTimeRangesEnd(segmentInfo.buffered, this.sourceUpdater_.buffered());
4123        timelineUpdated = updateSegmentMetadata(playlist, currentMediaIndex, segmentEnd);
4124      }
4125
4126      return timelineUpdated;
4127    }
4128
4129    /**
4130     * add a number of seconds to the currentTime when determining which
4131     * segment to fetch in order to force the fetcher to advance in cases
4132     * where it may get stuck on the same segment due to buffer gaps or
4133     * missing segment annotation after a rendition switch (especially
4134     * during a live stream)
4135     *
4136     * @private
4137     * @param {Number} secondsToIncrement number of seconds to add to the
4138     * timeCorrection_ variable
4139     * @param {Number} maxSegmentsToWalk maximum number of times we allow this
4140     * function to walk forward
4141     */
4142  }, {
4143    key: 'incrementTimeCorrection_',
4144    value: function incrementTimeCorrection_(secondsToIncrement, maxSegmentsToWalk) {
4145      // If we have already incremented timeCorrection_ beyond the limit,
4146      // stop searching for a segment and reset timeCorrection_
4147      if (this.timeCorrection_ >= this.playlist_.targetDuration * maxSegmentsToWalk) {
4148        this.timeCorrection_ = 0;
4149        return false;
4150      }
4151
4152      this.timeCorrection_ += secondsToIncrement;
4153      return true;
4154    }
4155  }]);
4156
4157  return SegmentLoader;
4158})(_videoJs2['default'].EventTarget);
4159
4160exports['default'] = SegmentLoader;
4161module.exports = exports['default'];
4162}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
4163},{"./config":3,"./playlist":7,"./ranges":8,"./source-updater":12,"aes-decrypter":18,"global/window":25,"mux.js/lib/mp4/probe":80}],12:[function(require,module,exports){
4164(function (global){
4165/**
4166 * @file source-updater.js
4167 */
4168'use strict';
4169
4170Object.defineProperty(exports, '__esModule', {
4171  value: true
4172});
4173
4174var _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; }; })();
4175
4176function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4177
4178function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
4179
4180var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
4181
4182var _videoJs2 = _interopRequireDefault(_videoJs);
4183
4184/**
4185 * A queue of callbacks to be serialized and applied when a
4186 * MediaSource and its associated SourceBuffers are not in the
4187 * updating state. It is used by the segment loader to update the
4188 * underlying SourceBuffers when new data is loaded, for instance.
4189 *
4190 * @class SourceUpdater
4191 * @param {MediaSource} mediaSource the MediaSource to create the
4192 * SourceBuffer from
4193 * @param {String} mimeType the desired MIME type of the underlying
4194 * SourceBuffer
4195 */
4196
4197var SourceUpdater = (function () {
4198  function SourceUpdater(mediaSource, mimeType) {
4199    var _this = this;
4200
4201    _classCallCheck(this, SourceUpdater);
4202
4203    var createSourceBuffer = function createSourceBuffer() {
4204      _this.sourceBuffer_ = mediaSource.addSourceBuffer(mimeType);
4205
4206      // run completion handlers and process callbacks as updateend
4207      // events fire
4208      _this.onUpdateendCallback_ = function () {
4209        var pendingCallback = _this.pendingCallback_;
4210
4211        _this.pendingCallback_ = null;
4212
4213        if (pendingCallback) {
4214          pendingCallback();
4215        }
4216
4217        _this.runCallback_();
4218      };
4219
4220      _this.sourceBuffer_.addEventListener('updateend', _this.onUpdateendCallback_);
4221
4222      _this.runCallback_();
4223    };
4224
4225    this.callbacks_ = [];
4226    this.pendingCallback_ = null;
4227    this.timestampOffset_ = 0;
4228    this.mediaSource = mediaSource;
4229
4230    if (mediaSource.readyState === 'closed') {
4231      mediaSource.addEventListener('sourceopen', createSourceBuffer);
4232    } else {
4233      createSourceBuffer();
4234    }
4235  }
4236
4237  /**
4238   * Aborts the current segment and resets the segment parser.
4239   *
4240   * @param {Function} done function to call when done
4241   * @see http://w3c.github.io/media-source/#widl-SourceBuffer-abort-void
4242   */
4243
4244  _createClass(SourceUpdater, [{
4245    key: 'abort',
4246    value: function abort(done) {
4247      var _this2 = this;
4248
4249      this.queueCallback_(function () {
4250        _this2.sourceBuffer_.abort();
4251      }, done);
4252    }
4253
4254    /**
4255     * Queue an update to append an ArrayBuffer.
4256     *
4257     * @param {ArrayBuffer} bytes
4258     * @param {Function} done the function to call when done
4259     * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-appendBuffer-void-ArrayBuffer-data
4260     */
4261  }, {
4262    key: 'appendBuffer',
4263    value: function appendBuffer(bytes, done) {
4264      var _this3 = this;
4265
4266      this.queueCallback_(function () {
4267        _this3.sourceBuffer_.appendBuffer(bytes);
4268      }, done);
4269    }
4270
4271    /**
4272     * Indicates what TimeRanges are buffered in the managed SourceBuffer.
4273     *
4274     * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-buffered
4275     */
4276  }, {
4277    key: 'buffered',
4278    value: function buffered() {
4279      if (!this.sourceBuffer_) {
4280        return _videoJs2['default'].createTimeRanges();
4281      }
4282      return this.sourceBuffer_.buffered;
4283    }
4284
4285    /**
4286     * Queue an update to set the duration.
4287     *
4288     * @param {Double} duration what to set the duration to
4289     * @see http://www.w3.org/TR/media-source/#widl-MediaSource-duration
4290     */
4291  }, {
4292    key: 'duration',
4293    value: function duration(_duration) {
4294      var _this4 = this;
4295
4296      this.queueCallback_(function () {
4297        _this4.sourceBuffer_.duration = _duration;
4298      });
4299    }
4300
4301    /**
4302     * Queue an update to remove a time range from the buffer.
4303     *
4304     * @param {Number} start where to start the removal
4305     * @param {Number} end where to end the removal
4306     * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-remove-void-double-start-unrestricted-double-end
4307     */
4308  }, {
4309    key: 'remove',
4310    value: function remove(start, end) {
4311      var _this5 = this;
4312
4313      this.queueCallback_(function () {
4314        _this5.sourceBuffer_.remove(start, end);
4315      });
4316    }
4317
4318    /**
4319     * wether the underlying sourceBuffer is updating or not
4320     *
4321     * @return {Boolean} the updating status of the SourceBuffer
4322     */
4323  }, {
4324    key: 'updating',
4325    value: function updating() {
4326      return !this.sourceBuffer_ || this.sourceBuffer_.updating;
4327    }
4328
4329    /**
4330     * Set/get the timestampoffset on the SourceBuffer
4331     *
4332     * @return {Number} the timestamp offset
4333     */
4334  }, {
4335    key: 'timestampOffset',
4336    value: function timestampOffset(offset) {
4337      var _this6 = this;
4338
4339      if (typeof offset !== 'undefined') {
4340        this.queueCallback_(function () {
4341          _this6.sourceBuffer_.timestampOffset = offset;
4342        });
4343        this.timestampOffset_ = offset;
4344      }
4345      return this.timestampOffset_;
4346    }
4347
4348    /**
4349     * que a callback to run
4350     */
4351  }, {
4352    key: 'queueCallback_',
4353    value: function queueCallback_(callback, done) {
4354      this.callbacks_.push([callback.bind(this), done]);
4355      this.runCallback_();
4356    }
4357
4358    /**
4359     * run a queued callback
4360     */
4361  }, {
4362    key: 'runCallback_',
4363    value: function runCallback_() {
4364      var callbacks = undefined;
4365
4366      if (this.sourceBuffer_ && !this.sourceBuffer_.updating && this.callbacks_.length) {
4367        callbacks = this.callbacks_.shift();
4368        this.pendingCallback_ = callbacks[1];
4369        callbacks[0]();
4370      }
4371    }
4372
4373    /**
4374     * dispose of the source updater and the underlying sourceBuffer
4375     */
4376  }, {
4377    key: 'dispose',
4378    value: function dispose() {
4379      this.sourceBuffer_.removeEventListener('updateend', this.onUpdateendCallback_);
4380      if (this.sourceBuffer_ && this.mediaSource.readyState === 'open') {
4381        this.sourceBuffer_.abort();
4382      }
4383    }
4384  }]);
4385
4386  return SourceUpdater;
4387})();
4388
4389exports['default'] = SourceUpdater;
4390module.exports = exports['default'];
4391}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
4392},{}],13:[function(require,module,exports){
4393/**
4394 * @file stream.js
4395 */
4396/**
4397 * A lightweight readable stream implemention that handles event dispatching.
4398 *
4399 * @class Stream
4400 */
4401'use strict';
4402
4403Object.defineProperty(exports, '__esModule', {
4404  value: true
4405});
4406
4407var _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; }; })();
4408
4409function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
4410
4411var Stream = (function () {
4412  function Stream() {
4413    _classCallCheck(this, Stream);
4414
4415    this.listeners = {};
4416  }
4417
4418  /**
4419   * Add a listener for a specified event type.
4420   *
4421   * @param {String} type the event name
4422   * @param {Function} listener the callback to be invoked when an event of
4423   * the specified type occurs
4424   */
4425
4426  _createClass(Stream, [{
4427    key: 'on',
4428    value: function on(type, listener) {
4429      if (!this.listeners[type]) {
4430        this.listeners[type] = [];
4431      }
4432      this.listeners[type].push(listener);
4433    }
4434
4435    /**
4436     * Remove a listener for a specified event type.
4437     *
4438     * @param {String} type the event name
4439     * @param {Function} listener  a function previously registered for this
4440     * type of event through `on`
4441     * @return {Boolean} if we could turn it off or not
4442     */
4443  }, {
4444    key: 'off',
4445    value: function off(type, listener) {
4446      var index = undefined;
4447
4448      if (!this.listeners[type]) {
4449        return false;
4450      }
4451      index = this.listeners[type].indexOf(listener);
4452      this.listeners[type].splice(index, 1);
4453      return index > -1;
4454    }
4455
4456    /**
4457     * Trigger an event of the specified type on this stream. Any additional
4458     * arguments to this function are passed as parameters to event listeners.
4459     *
4460     * @param {String} type the event name
4461     */
4462  }, {
4463    key: 'trigger',
4464    value: function trigger(type) {
4465      var callbacks = undefined;
4466      var i = undefined;
4467      var length = undefined;
4468      var args = undefined;
4469
4470      callbacks = this.listeners[type];
4471      if (!callbacks) {
4472        return;
4473      }
4474      // Slicing the arguments on every invocation of this method
4475      // can add a significant amount of overhead. Avoid the
4476      // intermediate object creation for the common case of a
4477      // single callback argument
4478      if (arguments.length === 2) {
4479        length = callbacks.length;
4480        for (i = 0; i < length; ++i) {
4481          callbacks[i].call(this, arguments[1]);
4482        }
4483      } else {
4484        args = Array.prototype.slice.call(arguments, 1);
4485        length = callbacks.length;
4486        for (i = 0; i < length; ++i) {
4487          callbacks[i].apply(this, args);
4488        }
4489      }
4490    }
4491
4492    /**
4493     * Destroys the stream and cleans up.
4494     */
4495  }, {
4496    key: 'dispose',
4497    value: function dispose() {
4498      this.listeners = {};
4499    }
4500
4501    /**
4502     * Forwards all `data` events on this stream to the destination stream. The
4503     * destination stream should provide a method `push` to receive the data
4504     * events as they arrive.
4505     *
4506     * @param {Stream} destination the stream that will receive all `data` events
4507     * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
4508     */
4509  }, {
4510    key: 'pipe',
4511    value: function pipe(destination) {
4512      this.on('data', function (data) {
4513        destination.push(data);
4514      });
4515    }
4516  }]);
4517
4518  return Stream;
4519})();
4520
4521exports['default'] = Stream;
4522module.exports = exports['default'];
4523},{}],14:[function(require,module,exports){
4524(function (global){
4525/**
4526 * @file xhr.js
4527 */
4528
4529/**
4530 * A wrapper for videojs.xhr that tracks bandwidth.
4531 *
4532 * @param {Object} options options for the XHR
4533 * @param {Function} callback the callback to call when done
4534 * @return {Request} the xhr request that is going to be made
4535 */
4536'use strict';
4537
4538Object.defineProperty(exports, '__esModule', {
4539  value: true
4540});
4541
4542var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
4543
4544var xhrFactory = function xhrFactory() {
4545  var xhr = function XhrFunction(options, callback) {
4546    // Add a default timeout for all hls requests
4547    options = (0, _videoJs.mergeOptions)({
4548      timeout: 45e3
4549    }, options);
4550
4551    // Allow an optional user-specified function to modify the option
4552    // object before we construct the xhr request
4553    if (XhrFunction.beforeRequest && typeof XhrFunction.beforeRequest === 'function') {
4554      var newOptions = XhrFunction.beforeRequest(options);
4555
4556      if (newOptions) {
4557        options = newOptions;
4558      }
4559    }
4560
4561    var request = (0, _videoJs.xhr)(options, function (error, response) {
4562      if (!error && request.response) {
4563        request.responseTime = new Date().getTime();
4564        request.roundTripTime = request.responseTime - request.requestTime;
4565        request.bytesReceived = request.response.byteLength || request.response.length;
4566        if (!request.bandwidth) {
4567          request.bandwidth = Math.floor(request.bytesReceived / request.roundTripTime * 8 * 1000);
4568        }
4569      }
4570
4571      // videojs.xhr now uses a specific code
4572      // on the error object to signal that a request has
4573      // timed out errors of setting a boolean on the request object
4574      if (error || request.timedout) {
4575        request.timedout = request.timedout || error.code === 'ETIMEDOUT';
4576      } else {
4577        request.timedout = false;
4578      }
4579
4580      // videojs.xhr no longer considers status codes outside of 200 and 0
4581      // (for file uris) to be errors, but the old XHR did, so emulate that
4582      // behavior. Status 206 may be used in response to byterange requests.
4583      if (!error && response.statusCode !== 200 && response.statusCode !== 206 && response.statusCode !== 0) {
4584        error = new Error('XHR Failed with a response of: ' + (request && (request.response || request.responseText)));
4585      }
4586
4587      callback(error, request);
4588    });
4589
4590    request.requestTime = new Date().getTime();
4591    return request;
4592  };
4593
4594  return xhr;
4595};
4596
4597exports['default'] = xhrFactory;
4598module.exports = exports['default'];
4599}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
4600},{}],15:[function(require,module,exports){
4601/**
4602 * @file aes.js
4603 *
4604 * This file contains an adaptation of the AES decryption algorithm
4605 * from the Standford Javascript Cryptography Library. That work is
4606 * covered by the following copyright and permissions notice:
4607 *
4608 * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
4609 * All rights reserved.
4610 *
4611 * Redistribution and use in source and binary forms, with or without
4612 * modification, are permitted provided that the following conditions are
4613 * met:
4614 *
4615 * 1. Redistributions of source code must retain the above copyright
4616 *    notice, this list of conditions and the following disclaimer.
4617 *
4618 * 2. Redistributions in binary form must reproduce the above
4619 *    copyright notice, this list of conditions and the following
4620 *    disclaimer in the documentation and/or other materials provided
4621 *    with the distribution.
4622 *
4623 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
4624 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4625 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4626 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
4627 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4628 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
4629 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
4630 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4631 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
4632 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
4633 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4634 *
4635 * The views and conclusions contained in the software and documentation
4636 * are those of the authors and should not be interpreted as representing
4637 * official policies, either expressed or implied, of the authors.
4638 */
4639
4640/**
4641 * Expand the S-box tables.
4642 *
4643 * @private
4644 */
4645'use strict';
4646
4647Object.defineProperty(exports, '__esModule', {
4648  value: true
4649});
4650
4651var _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; }; })();
4652
4653function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
4654
4655var precompute = function precompute() {
4656  var tables = [[[], [], [], [], []], [[], [], [], [], []]];
4657  var encTable = tables[0];
4658  var decTable = tables[1];
4659  var sbox = encTable[4];
4660  var sboxInv = decTable[4];
4661  var i = undefined;
4662  var x = undefined;
4663  var xInv = undefined;
4664  var d = [];
4665  var th = [];
4666  var x2 = undefined;
4667  var x4 = undefined;
4668  var x8 = undefined;
4669  var s = undefined;
4670  var tEnc = undefined;
4671  var tDec = undefined;
4672
4673  // Compute double and third tables
4674  for (i = 0; i < 256; i++) {
4675    th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
4676  }
4677
4678  for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
4679    // Compute sbox
4680    s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
4681    s = s >> 8 ^ s & 255 ^ 99;
4682    sbox[x] = s;
4683    sboxInv[s] = x;
4684
4685    // Compute MixColumns
4686    x8 = d[x4 = d[x2 = d[x]]];
4687    tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
4688    tEnc = d[s] * 0x101 ^ s * 0x1010100;
4689
4690    for (i = 0; i < 4; i++) {
4691      encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
4692      decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
4693    }
4694  }
4695
4696  // Compactify. Considerable speedup on Firefox.
4697  for (i = 0; i < 5; i++) {
4698    encTable[i] = encTable[i].slice(0);
4699    decTable[i] = decTable[i].slice(0);
4700  }
4701  return tables;
4702};
4703var aesTables = null;
4704
4705/**
4706 * Schedule out an AES key for both encryption and decryption. This
4707 * is a low-level class. Use a cipher mode to do bulk encryption.
4708 *
4709 * @class AES
4710 * @param key {Array} The key as an array of 4, 6 or 8 words.
4711 */
4712
4713var AES = (function () {
4714  function AES(key) {
4715    _classCallCheck(this, AES);
4716
4717    /**
4718     * The expanded S-box and inverse S-box tables. These will be computed
4719     * on the client so that we don't have to send them down the wire.
4720     *
4721     * There are two tables, _tables[0] is for encryption and
4722     * _tables[1] is for decryption.
4723     *
4724     * The first 4 sub-tables are the expanded S-box with MixColumns. The
4725     * last (_tables[01][4]) is the S-box itself.
4726     *
4727     * @private
4728     */
4729    // if we have yet to precompute the S-box tables
4730    // do so now
4731    if (!aesTables) {
4732      aesTables = precompute();
4733    }
4734    // then make a copy of that object for use
4735    this._tables = [[aesTables[0][0].slice(), aesTables[0][1].slice(), aesTables[0][2].slice(), aesTables[0][3].slice(), aesTables[0][4].slice()], [aesTables[1][0].slice(), aesTables[1][1].slice(), aesTables[1][2].slice(), aesTables[1][3].slice(), aesTables[1][4].slice()]];
4736    var i = undefined;
4737    var j = undefined;
4738    var tmp = undefined;
4739    var encKey = undefined;
4740    var decKey = undefined;
4741    var sbox = this._tables[0][4];
4742    var decTable = this._tables[1];
4743    var keyLen = key.length;
4744    var rcon = 1;
4745
4746    if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
4747      throw new Error('Invalid aes key size');
4748    }
4749
4750    encKey = key.slice(0);
4751    decKey = [];
4752    this._key = [encKey, decKey];
4753
4754    // schedule encryption keys
4755    for (i = keyLen; i < 4 * keyLen + 28; i++) {
4756      tmp = encKey[i - 1];
4757
4758      // apply sbox
4759      if (i % keyLen === 0 || keyLen === 8 && i % keyLen === 4) {
4760        tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255];
4761
4762        // shift rows and add rcon
4763        if (i % keyLen === 0) {
4764          tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
4765          rcon = rcon << 1 ^ (rcon >> 7) * 283;
4766        }
4767      }
4768
4769      encKey[i] = encKey[i - keyLen] ^ tmp;
4770    }
4771
4772    // schedule decryption keys
4773    for (j = 0; i; j++, i--) {
4774      tmp = encKey[j & 3 ? i : i - 4];
4775      if (i <= 4 || j < 4) {
4776        decKey[j] = tmp;
4777      } else {
4778        decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[3][sbox[tmp & 255]];
4779      }
4780    }
4781  }
4782
4783  /**
4784   * Decrypt 16 bytes, specified as four 32-bit words.
4785   *
4786   * @param {Number} encrypted0 the first word to decrypt
4787   * @param {Number} encrypted1 the second word to decrypt
4788   * @param {Number} encrypted2 the third word to decrypt
4789   * @param {Number} encrypted3 the fourth word to decrypt
4790   * @param {Int32Array} out the array to write the decrypted words
4791   * into
4792   * @param {Number} offset the offset into the output array to start
4793   * writing results
4794   * @return {Array} The plaintext.
4795   */
4796
4797  _createClass(AES, [{
4798    key: 'decrypt',
4799    value: function decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) {
4800      var key = this._key[1];
4801      // state variables a,b,c,d are loaded with pre-whitened data
4802      var a = encrypted0 ^ key[0];
4803      var b = encrypted3 ^ key[1];
4804      var c = encrypted2 ^ key[2];
4805      var d = encrypted1 ^ key[3];
4806      var a2 = undefined;
4807      var b2 = undefined;
4808      var c2 = undefined;
4809
4810      // key.length === 2 ?
4811      var nInnerRounds = key.length / 4 - 2;
4812      var i = undefined;
4813      var kIndex = 4;
4814      var table = this._tables[1];
4815
4816      // load up the tables
4817      var table0 = table[0];
4818      var table1 = table[1];
4819      var table2 = table[2];
4820      var table3 = table[3];
4821      var sbox = table[4];
4822
4823      // Inner rounds. Cribbed from OpenSSL.
4824      for (i = 0; i < nInnerRounds; i++) {
4825        a2 = table0[a >>> 24] ^ table1[b >> 16 & 255] ^ table2[c >> 8 & 255] ^ table3[d & 255] ^ key[kIndex];
4826        b2 = table0[b >>> 24] ^ table1[c >> 16 & 255] ^ table2[d >> 8 & 255] ^ table3[a & 255] ^ key[kIndex + 1];
4827        c2 = table0[c >>> 24] ^ table1[d >> 16 & 255] ^ table2[a >> 8 & 255] ^ table3[b & 255] ^ key[kIndex + 2];
4828        d = table0[d >>> 24] ^ table1[a >> 16 & 255] ^ table2[b >> 8 & 255] ^ table3[c & 255] ^ key[kIndex + 3];
4829        kIndex += 4;
4830        a = a2;b = b2;c = c2;
4831      }
4832
4833      // Last round.
4834      for (i = 0; i < 4; i++) {
4835        out[(3 & -i) + offset] = sbox[a >>> 24] << 24 ^ sbox[b >> 16 & 255] << 16 ^ sbox[c >> 8 & 255] << 8 ^ sbox[d & 255] ^ key[kIndex++];
4836        a2 = a;a = b;b = c;c = d;d = a2;
4837      }
4838    }
4839  }]);
4840
4841  return AES;
4842})();
4843
4844exports['default'] = AES;
4845module.exports = exports['default'];
4846},{}],16:[function(require,module,exports){
4847/**
4848 * @file async-stream.js
4849 */
4850'use strict';
4851
4852Object.defineProperty(exports, '__esModule', {
4853  value: true
4854});
4855
4856var _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; }; })();
4857
4858var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
4859
4860function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4861
4862function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
4863
4864function _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, { c
4864onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
4865
4866var _stream = require('./stream');
4867
4868var _stream2 = _interopRequireDefault(_stream);
4869
4870/**
4871 * A wrapper around the Stream class to use setTiemout
4872 * and run stream "jobs" Asynchronously
4873 *
4874 * @class AsyncStream
4875 * @extends Stream
4876 */
4877
4878var AsyncStream = (function (_Stream) {
4879  _inherits(AsyncStream, _Stream);
4880
4881  function AsyncStream() {
4882    _classCallCheck(this, AsyncStream);
4883
4884    _get(Object.getPrototypeOf(AsyncStream.prototype), 'constructor', this).call(this, _stream2['default']);
4885    this.jobs = [];
4886    this.delay = 1;
4887    this.timeout_ = null;
4888  }
4889
4890  /**
4891   * process an async job
4892   *
4893   * @private
4894   */
4895
4896  _createClass(AsyncStream, [{
4897    key: 'processJob_',
4898    value: function processJob_() {
4899      this.jobs.shift()();
4900      if (this.jobs.length) {
4901        this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay);
4902      } else {
4903        this.timeout_ = null;
4904      }
4905    }
4906
4907    /**
4908     * push a job into the stream
4909     *
4910     * @param {Function} job the job to push into the stream
4911     */
4912  }, {
4913    key: 'push',
4914    value: function push(job) {
4915      this.jobs.push(job);
4916      if (!this.timeout_) {
4917        this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay);
4918      }
4919    }
4920  }]);
4921
4922  return AsyncStream;
4923})(_stream2['default']);
4924
4925exports['default'] = AsyncStream;
4926module.exports = exports['default'];
4927},{"./stream":19}],17:[function(require,module,exports){
4928/**
4929 * @file decrypter.js
4930 *
4931 * An asynchronous implementation of AES-128 CBC decryption with
4932 * PKCS#7 padding.
4933 */
4934
4935'use strict';
4936
4937Object.defineProperty(exports, '__esModule', {
4938  value: true
4939});
4940
4941var _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; }; })();
4942
4943function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4944
4945function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
4946
4947var _aes = require('./aes');
4948
4949var _aes2 = _interopRequireDefault(_aes);
4950
4951var _asyncStream = require('./async-stream');
4952
4953var _asyncStream2 = _interopRequireDefault(_asyncStream);
4954
4955var _pkcs7 = require('pkcs7');
4956
4957/**
4958 * Convert network-order (big-endian) bytes into their little-endian
4959 * representation.
4960 */
4961var ntoh = function ntoh(word) {
4962  return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24;
4963};
4964
4965/**
4966 * Decrypt bytes using AES-128 with CBC and PKCS#7 padding.
4967 *
4968 * @param {Uint8Array} encrypted the encrypted bytes
4969 * @param {Uint32Array} key the bytes of the decryption key
4970 * @param {Uint32Array} initVector the initialization vector (IV) to
4971 * use for the first round of CBC.
4972 * @return {Uint8Array} the decrypted bytes
4973 *
4974 * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
4975 * @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29
4976 * @see https://tools.ietf.org/html/rfc2315
4977 */
4978var decrypt = function decrypt(encrypted, key, initVector) {
4979  // word-level access to the encrypted bytes
4980  var encrypted32 = new Int32Array(encrypted.buffer, encrypted.byteOffset, encrypted.byteLength >> 2);
4981
4982  var decipher = new _aes2['default'](Array.prototype.slice.call(key));
4983
4984  // byte and word-level access for the decrypted output
4985  var decrypted = new Uint8Array(encrypted.byteLength);
4986  var decrypted32 = new Int32Array(decrypted.buffer);
4987
4988  // temporary variables for working with the IV, encrypted, and
4989  // decrypted data
4990  var init0 = undefined;
4991  var init1 = undefined;
4992  var init2 = undefined;
4993  var init3 = undefined;
4994  var encrypted0 = undefined;
4995  var encrypted1 = undefined;
4996  var encrypted2 = undefined;
4997  var encrypted3 = undefined;
4998
4999  // iteration variable
5000  var wordIx = undefined;
5001
5002  // pull out the words of the IV to ensure we don't modify the
5003  // passed-in reference and easier access
5004  init0 = initVector[0];
5005  init1 = initVector[1];
5006  init2 = initVector[2];
5007  init3 = initVector[3];
5008
5009  // decrypt four word sequences, applying cipher-block chaining (CBC)
5010  // to each decrypted block
5011  for (wordIx = 0;
5011 wordIx < encrypted32.length; wordIx += 4) {
5012    // convert big-endian (network order) words into little-endian
5013    // (javascript order)
5014    encrypted0 = ntoh(encrypted32[wordIx]);
5015    encrypted1 = ntoh(encrypted32[wordIx + 1]);
5016    encrypted2 = ntoh(encrypted32[wordIx + 2]);
5017    encrypted3 = ntoh(encrypted32[wordIx + 3]);
5018
5019    // decrypt the block
5020    decipher.decrypt(encrypted0, encrypted1, encrypted2, encrypted3, decrypted32, wordIx);
5021
5022    // XOR with the IV, and restore network byte-order to obtain the
5023    // plaintext
5024    decrypted32[wordIx] = ntoh(decrypted32[wordIx] ^ init0);
5025    decrypted32[wordIx + 1] = ntoh(decrypted32[wordIx + 1] ^ init1);
5026    decrypted32[wordIx + 2] = ntoh(decrypted32[wordIx + 2] ^ init2);
5027    decrypted32[wordIx + 3] = ntoh(decrypted32[wordIx + 3] ^ init3);
5028
5029    // setup the IV for the next round
5030    init0 = encrypted0;
5031    init1 = encrypted1;
5032    init2 = encrypted2;
5033    init3 = encrypted3;
5034  }
5035
5036  return decrypted;
5037};
5038
5039exports.decrypt = decrypt;
5040/**
5041 * The `Decrypter` class that manages decryption of AES
5042 * data through `AsyncStream` objects and the `decrypt`
5043 * function
5044 *
5045 * @param {Uint8Array} encrypted the encrypted bytes
5046 * @param {Uint32Array} key the bytes of the decryption key
5047 * @param {Uint32Array} initVector the initialization vector (IV) to
5048 * @param {Function} done the function to run when done
5049 * @class Decrypter
5050 */
5051
5052var Decrypter = (function () {
5053  function Decrypter(encrypted, key, initVector, done) {
5054    _classCallCheck(this, Decrypter);
5055
5056    var step = Decrypter.STEP;
5057    var encrypted32 = new Int32Array(encrypted.buffer);
5058    var decrypted = new Uint8Array(encrypted.byteLength);
5059    var i = 0;
5060
5061    this.asyncStream_ = new _asyncStream2['default']();
5062
5063    // split up the encryption job and do the individual chunks asynchronously
5064    this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));
5065    for (i = step; i < encrypted32.length; i += step) {
5066      initVector = new Uint32Array([ntoh(encrypted32[i - 4]), ntoh(encrypted32[i - 3]), ntoh(encrypted32[i - 2]), ntoh(encrypted32[i - 1])]);
5067      this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));
5068    }
5069    // invoke the done() callback when everything is finished
5070    this.asyncStream_.push(function () {
5071      // remove pkcs#7 padding from the decrypted bytes
5072      done(null, (0, _pkcs7.unpad)(decrypted));
5073    });
5074  }
5075
5076  /**
5077   * a getter for step the maximum number of bytes to process at one time
5078   *
5079   * @return {Number} the value of step 32000
5080   */
5081
5082  _createClass(Decrypter, [{
5083    key: 'decryptChunk_',
5084
5085    /**
5086     * @private
5087     */
5088    value: function decryptChunk_(encrypted, key, initVector, decrypted) {
5089      return function () {
5090        var bytes = decrypt(encrypted, key, initVector);
5091
5092        decrypted.set(bytes, encrypted.byteOffset);
5093      };
5094    }
5095  }], [{
5096    key: 'STEP',
5097    get: function get() {
5098      // 4 * 8000;
5099      return 32000;
5100    }
5101  }]);
5102
5103  return Decrypter;
5104})();
5105
5106exports.Decrypter = Decrypter;
5107exports['default'] = {
5108  Decrypter: Decrypter,
5109  decrypt: decrypt
5110};
5111},{"./aes":15,"./async-stream":16,"pkcs7":21}],18:[function(require,module,exports){
5112/**
5113 * @file index.js
5114 *
5115 * Index module to easily import the primary components of AES-128
5116 * decryption. Like this:
5117 *
5118 * ```js
5119 * import {Decrypter, decrypt, AsyncStream} from 'aes-decrypter';
5120 * ```
5121 */
5122'use strict';
5123
5124Object.defineProperty(exports, '__esModule', {
5125  value: true
5126});
5127
5128function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
5129
5130var _decrypter = require('./decrypter');
5131
5132var _asyncStream = require('./async-stream');
5133
5134var _asyncStream2 = _interopRequireDefault(_asyncStream);
5135
5136exports['default'] = {
5137  decrypt: _decrypter.decrypt,
5138  Decrypter: _decrypter.Decrypter,
5139  AsyncStream: _asyncStream2['default']
5140};
5141module.exports = exports['default'];
5142},{"./async-stream":16,"./decrypter":17}],19:[function(require,module,exports){
5143arguments[4][13][0].apply(exports,arguments)
5144},{"dup":13}],20:[function(require,module,exports){
5145/*
5146 * pkcs7.pad
5147 * https://github.com/brightcove/pkcs7
5148 *
5149 * Copyright (c) 2014 Brightcove
5150 * Licensed under the apache2 license.
5151 */
5152
5153'use strict';
5154
5155var PADDING;
5156
5157/**
5158 * Returns a new Uint8Array that is padded with PKCS#7 padding.
5159 * @param plaintext {Uint8Array} the input bytes before encryption
5160 * @return {Uint8Array} the padded bytes
5161 * @see http://tools.ietf.org/html/rfc5652
5162 */
5163module.exports = function pad(plaintext) {
5164  var padding = PADDING[(plaintext.byteLength % 16) || 0],
5165      result = new Uint8Array(plaintext.byteLength + padding.length);
5166  result.set(plaintext);
5167  result.set(padding, plaintext.byteLength);
5168  return result;
5169};
5170
5171// pre-define the padding values
5172PADDING = [
5173  [16, 16, 16, 16,
5174   16, 16, 16, 16,
5175   16, 16, 16, 16,
5176   16, 16, 16, 16],
5177
5178  [15, 15, 15, 15,
5179   15, 15, 15, 15,
5180   15, 15, 15, 15,
5181   15, 15, 15],
5182
5183  [14, 14, 14, 14,
5184   14, 14, 14, 14,
5185   14, 14, 14, 14,
5186   14, 14],
5187
5188  [13, 13, 13, 13,
5189   13, 13, 13, 13,
5190   13, 13, 13, 13,
5191   13],
5192
5193  [12, 12, 12, 12,
5194   12, 12, 12, 12,
5195   12, 12, 12, 12],
5196
5197  [11, 11, 11, 11,
5198   11, 11, 11, 11,
5199   11, 11, 11],
5200
5201  [10, 10, 10, 10,
5202   10, 10, 10, 10,
5203   10, 10],
5204
5205  [9, 9, 9, 9,
5206   9, 9, 9, 9,
5207   9],
5208
5209  [8, 8, 8, 8,
5210   8, 8, 8, 8],
5211
5212  [7, 7, 7, 7,
5213   7, 7, 7],
5214
5215  [6, 6, 6, 6,
5216   6, 6],
5217
5218  [5, 5, 5, 5,
5219   5],
5220
5221  [4, 4, 4, 4],
5222
5223  [3, 3, 3],
5224
5225  [2, 2],
5226
5227  [1]
5228];
5229
5230},{}],21:[function(require,module,exports){
5231/*
5232 * pkcs7
5233 * https://github.com/brightcove/pkcs7
5234 *
5235 * Copyright (c) 2014 Brightcove
5236 * Licensed under the apache2 license.
5237 */
5238
5239'use strict';
5240
5241exports.pad = require('./pad.js');
5242exports.unpad = require('./unpad.js');
5243
5244},{"./pad.js":20,"./unpad.js":22}],22:[function(require,module,exports){
5245/*
5246 * pkcs7.unpad
5247 * https://github.com/brightcove/pkcs7
5248 *
5249 * Copyright (c) 2014 Brightcove
5250 * Licensed under the apache2 license.
5251 */
5252
5253'use strict';
5254
5255/**
5256 * Returns the subarray of a Uint8Array without PKCS#7 padding.
5257 * @param padded {Uint8Array} unencrypted bytes that have been padded
5258 * @return {Uint8Array} the unpadded bytes
5259 * @see http://tools.ietf.org/html/rfc5652
5260 */
5261module.exports = function unpad(padded) {
5262  return padded.subarray(0, padded.byteLength - padded[padded.byteLength - 1]);
5263};
5264
5265},{}],23:[function(require,module,exports){
5266
5267},{}],24:[function(require,module,exports){
5268(function (global){
5269var topLevel = typeof global !== 'undefined' ? global :
5270    typeof window !== 'undefined' ? window : {}
5271var minDoc = require('min-document');
5272
5273if (typeof document !== 'undefined') {
5274    module.exports = document;
5275} else {
5276    var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
5277
5278    if (!doccy) {
5279        doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
5280    }
5281
5282    module.exports = doccy;
5283}
5284
5285}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
5286},{"min-document":23}],25:[function(require,module,exports){
5287(function (global){
5288if (typeof window !== "undefined") {
5289    module.exports = window;
5290} else if (typeof global !== "undefined") {
5291    module.exports = global;
5292} else if (typeof self !== "undefined"){
5293    module.exports = self;
5294} else {
5295    module.exports = {};
5296}
5297
5298}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
5299},{}],26:[function(require,module,exports){
5300/** Used as the `TypeError` message for "Functions" methods. */
5301var FUNC_ERROR_TEXT = 'Expected a function';
5302
5303/* Native method references for those with the same name as other `lodash` methods. */
5304var nativeMax = Math.max;
5305
5306/**
5307 * Creates a function that invokes `func` with the `this` binding of the
5308 * created function and arguments from `start` and beyond provided as an array.
5309 *
5310 * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/Web/JavaScript/Reference/Functions/rest_parameters).
5311 *
5312 * @static
5313 * @memberOf _
5314 * @category Function
5315 * @param {Function} func The function to apply a rest parameter to.
5316 * @param {number} [start=func.length-1] The start position of the rest parameter.
5317 * @returns {Function} Returns the new function.
5318 * @example
5319 *
5320 * var say = _.restParam(function(what, names) {
5321 *   return what + ' ' + _.initial(names).join(', ') +
5322 *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
5323 * });
5324 *
5325 * say('hello', 'fred', 'barney', 'pebbles');
5326 * // => 'hello fred, barney, & pebbles'
5327 */
5328function restParam(func, start) {
5329  if (typeof func != 'function') {
5330    throw new TypeError(FUNC_ERROR_TEXT);
5331  }
5332  start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
5333  return function() {
5334    var args = arguments,
5335        index = -1,
5336        length = nativeMax(args.length - start, 0),
5337        rest = Array(length);
5338
5339    while (++index < length) {
5340      rest[index] = args[start + index];
5341    }
5342    switch (start) {
5343      case 0: return func.call(this, rest);
5344      case 1: return func.call(this, args[0], rest);
5345      case 2: return func.call(this, args[0], args[1], rest);
5346    }
5347    var otherArgs = Array(start + 1);
5348    index = -1;
5349    while (++index < start) {
5350      otherArgs[index] = args[index];
5351    }
5352    otherArgs[start] = rest;
5353    return func.apply(this, otherArgs);
5354  };
5355}
5356
5357module.exports = restParam;
5358
5359},{}],27:[function(require,module,exports){
5360/**
5361 * Copies the values of `source` to `array`.
5362 *
5363 * @private
5364 * @param {Array} source The array to copy values from.
5365 * @param {Array} [array=[]] The array to copy values to.
5366 * @returns {Array} Returns `array`.
5367 */
5368function arrayCopy(source, array) {
5369  var index = -1,
5370      length = source.length;
5371
5372  array || (array = Array(length));
5373  while (++index < length) {
5374    array[index] = source[index];
5375  }
5376  return array;
5377}
5378
5379module.exports = arrayCopy;
5380
5381},{}],28:[function(require,module,exports){
5382/**
5383 * A specialized version of `_.forEach` for arrays without support for callback
5384 * shorthands and `this` binding.
5385 *
5386 * @private
5387 * @param {Array} array The array to iterate over.
5388 * @param {Function} iteratee The function invoked per iteration.
5389 * @returns {Array} Returns `array`.
5390 */
5391function arrayEach(array, iteratee) {
5392  var index = -1,
5393      length = array.length;
5394
5395  while (++index < length) {
5396    if (iteratee(array[index], index, array) === false) {
5397      break;
5398    }
5399  }
5400  return array;
5401}
5402
5403module.exports = arrayEach;
5404
5405},{}],29:[function(require,module,exports){
5406/**
5407 * Copies properties of `source` to `object`.
5408 *
5409 * @private
5410 * @param {Object} source The object to copy properties from.
5411 * @param {Array} props The property names to copy.
5412 * @param {Object} [object={}] The object to copy properties to.
5413 * @returns {Object} Returns `object`.
5414 */
5415function baseCopy(source, props, object) {
5416  object || (object = {});
5417
5418  var index = -1,
5419      length = props.length;
5420
5421  while (++index < length) {
5422    var key = props[index];
5423    object[key] = source[key];
5424  }
5425  return object;
5426}
5427
5428module.exports = baseCopy;
5429
5430},{}],30:[function(require,module,exports){
5431var createBaseFor = require('./createBaseFor');
5432
5433/**
5434 * The base implementation of `baseForIn` and `baseForOwn` which iterates
5435 * over `object` properties returned by `keysFunc` invoking `iteratee` for
5436 * each property. Iteratee functions may exit iteration early by explicitly
5437 * returning `false`.
5438 *
5439 * @private
5440 * @param {Object} object The object to iterate over.
5441 * @param {Function} iteratee The function invoked per iteration.
5442 * @param {Function} keysFunc The function to get the keys of `object`.
5443 * @returns {Object} Returns `object`.
5444 */
5445var baseFor = createBaseFor();
5446
5447module.exports = baseFor;
5448
5449},{"./createBaseFor":37}],31:[function(require,module,exports){
5450var baseFor = require('./baseFor'),
5451    keysIn = require('../object/keysIn');
5452
5453/**
5454 * The base implementation of `_.forIn` without support for callback
5455 * shorthands and `this` binding.
5456 *
5457 * @private
5458 * @param {Object} object The object to iterate over.
5459 * @param {Function} iteratee The function invoked per iteration.
5460 * @returns {Object} Returns `object`.
5461 */
5462function baseForIn(object, iteratee) {
5463  return baseFor(object, iteratee, keysIn);
5464}
5465
5466module.exports = baseForIn;
5467
5468},{"../object/keysIn":58,"./baseFor":30}],32:[function(require,module,exports){
5469var arrayEach = require('./arrayEach'),
5470    baseMergeDeep = require('./baseMergeDeep'),
5471    isArray = require('../lang/isArray'),
5472    isArrayLike = require('./isArrayLike'),
5473    isObject = require('../lang/isObject'),
5474    isObjectLike = require('./isObjectLike'),
5475    isTypedArray = require('../lang/isTypedArray'),
5476    keys = require('../object/keys');
5477
5478/**
5479 * The base implementation of `_.merge` without support for argument juggling,
5480 * multiple sources, and `this` binding `customizer` functions.
5481 *
5482 * @private
5483 * @param {Object} object The destination object.
5484 * @param {Object} source The source object.
5485 * @param {Function} [customizer] The function to customize merged values.
5486 * @param {Array} [stackA=[]] Tracks traversed source objects.
5487 * @param {Array} [stackB=[]] Associates values with source counterparts.
5488 * @returns {Object} Returns `object`.
5489 */
5490function baseMerge(object, source, customizer, stackA, stackB) {
5491  if (!isObject(object)) {
5492    return object;
5493  }
5494  var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)),
5495      props = isSrcArr ? undefined : keys(source);
5496
5497  arrayEach(props || source, function(srcValue, key) {
5498    if (props) {
5499      key = srcValue;
5500      srcValue = source[key];
5501    }
5502    if (isObjectLike(srcValue)) {
5503      stackA || (stackA = []);
5504      stackB || (stackB = []);
5505      baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
5506    }
5507    else {
5508      var value = object[key],
5509          result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
5510          isCommon = result === undefined;
5511
5512      if (isCommon) {
5513        result = srcValue;
5514      }
5515      if ((result !== undefined || (isSrcArr && !(key in object))) &&
5516          (isCommon || (result === result ? (result !== value) : (value === value)))) {
5517        object[key] = result;
5518      }
5519    }
5520  });
5521  return object;
5522}
5523
5524module.exports = baseMerge;
5525
5526},{"../lang/isArray":49,"../lang/isObject":52,"../lang/isTypedArray":55,"../object/keys":57,"./arrayEach":28,"./baseMergeDeep":33,"./isArrayLike":40,"./isObjectLike":45}],33:[function(require,module,exports){
5527var arrayCopy = require('./arrayCopy'),
5528    isArguments = require('../lang/isArguments'),
5529    isArray = require('../lang/isArray'),
5530    isArrayLike = require('./isArrayLike'),
5531    isPlainObject = require('../lang/isPlainObject'),
5532    isTypedArray = require('../lang/isTypedArray'),
5533    toPlainObject = require('../lang/toPlainObject');
5534
5535/**
5536 * A specialized version of `baseMerge` for arrays and objects which performs
5537 * deep merges and tracks traversed objects enabling objects with circular
5538 * references to be merged.
5539 *
5540 * @private
5541 * @param {Object} object The destination object.
5542 * @param {Object} source The source object.
5543 * @param {string} key The key of the value to merge.
5544 * @param {Function} mergeFunc The function to merge values.
5545 * @param {Function} [customizer] The function to customize merged values.
5546 * @param {Array} [stackA=[]] Tracks traversed source objects.
5547 * @param {Array} [stackB=[]] Associates values with source counterparts.
5548 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
5549 */
5550function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
5551  var length = stackA.length,
5552      srcValue = source[key];
5553
5554  while (length--) {
5555    if (stackA[length] == srcValue) {
5556      object[key] = stackB[length];
5557      return;
5558    }
5559  }
5560  var value = object[key],
5561      result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
5562      isCommon = result === undefined;
5563
5564  if (isCommon) {
5565    result = srcValue;
5566    if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) {
5567      result = isArray(value)
5568        ? value
5569        : (isArrayLike(value) ? arrayCopy(value) : []);
5570    }
5571    else if (isPlainObject(srcValue) || isArguments(srcValue)) {
5572      result = isArguments(value)
5573        ? toPlainObject(value)
5574        : (isPlainObject(value) ? value : {});
5575    }
5576    else {
5577      isCommon = false;
5578    }
5579  }
5580  // Add the source value to the stack of traversed objects and associate
5581  // it with its merged value.
5582  stackA.push(srcValue);
5583  stackB.push(result);
5584
5585  if (isCommon) {
5586    // Recursively merge objects and arrays (susceptible to call stack limits).
5587    object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
5588  } else if (result === result ? (result !== value) : (value === value)) {
5589    object[key] = result;
5590  }
5591}
5592
5593module.exports = baseMergeDeep;
5594
5595},{"../lang/isArguments":48,"../lang/isArray":49,"../lang/isPlainObject":53,"../lang/isTypedArray":55,"../lang/toPlainObject":56,"./arrayCopy":27,"./isArrayLike":40}],34:[function(require,module,exports){
5596var toObject = require('./toObject');
5597
5598/**
5599 * The base implementation of `_.property` without support for deep paths.
5600 *
5601 * @private
5602 * @param {string} key The key of the property to get.
5603 * @returns {Function} Returns the new function.
5604 */
5605function baseProperty(key) {
5606  return function(object) {
5607    return object == null ? undefined : toObject(object)[key];
5608  };
5609}
5610
5611module.exports = baseProperty;
5612
5613},{"./toObject":47}],35:[function(require,module,exports){
5614var identity = require('../utility/identity');
5615
5616/**
5617 * A specialized version of `baseCallback` which only supports `this` binding
5618 * and specifying the number of arguments to provide to `func`.
5619 *
5620 * @private
5621 * @param {Function} func The function to bind.
5622 * @param {*} thisArg The `this` binding of `func`.
5623 * @param {number} [argCount] The number of arguments to provide to `func`.
5624 * @returns {Function} Returns the callback.
5625 */
5626function bindCallback(func, thisArg, argCount) {
5627  if (typeof func != 'function') {
5628    return identity;
5629  }
5630  if (thisArg === undefined) {
5631    return func;
5632  }
5633  switch (argCount) {
5634    case 1: return function(value) {
5635      return func.call(thisArg, value);
5636    };
5637    case 3: return function(value, index, collection) {
5638      return func.call(thisArg, value, index, collection);
5639    };
5640    case 4: return function(accumulator, value, index, collection) {
5641      return func.call(thisArg, accumulator, value, index, collection);
5642    };
5643    case 5: return function(value, other, key, object, source) {
5644      return func.call(thisArg, value, other, key, object, source);
5645    };
5646  }
5647  return function() {
5648    return func.apply(thisArg, arguments);
5649  };
5650}
5651
5652module.exports = bindCallback;
5653
5654},{"../utility/identity":61}],36:[function(require,module,exports){
5655var bindCallback = require('./bindCallback'),
5656    isIterateeCall = require('./isIterateeCall'),
5657    restParam = require('../function/restParam');
5658
5659/**
5660 * Creates a `_.assign`, `_.defaults`, or `_.merge` function.
5661 *
5662 * @private
5663 * @param {Function} assigner The function to assign values.
5664 * @returns {Function} Returns the new assigner function.
5665 */
5666function createAssigner(assigner) {
5667  return restParam(function(object, sources) {
5668    var index = -1,
5669        length = object == null ? 0 : sources.length,
5670        customizer = length > 2 ? sources[length - 2] : undefined,
5671        guard = length > 2 ? sources[2] : undefined,
5672        thisArg = length > 1 ? sources[length - 1] : undefined;
5673
5674    if (typeof customizer == 'function') {
5675      customizer = bindCallback(customizer, thisArg, 5);
5676      length -= 2;
5677    } else {
5678      customizer = typeof thisArg == 'function' ? thisArg : undefined;
5679      length -= (customizer ? 1 : 0);
5680    }
5681    if (guard && isIterateeCall(sources[0], sources[1], guard)) {
5682      customizer = length < 3 ? undefined : customizer;
5683      length = 1;
5684    }
5685    while (++index < length) {
5686      var source = sources[index];
5687      if (source) {
5688        assigner(object, source, customizer);
5689      }
5690    }
5691    return object;
5692  });
5693}
5694
5695module.exports = createAssigner;
5696
5697},{"../function/restParam":26,"./bindCallback":35,"./isIterateeCall":43}],37:[function(require,module,exports){
5698var toObject = require('./toObject');
5699
5700/**
5701 * Creates a base function for `_.forIn` or `_.forInRight`.
5702 *
5703 * @private
5704 * @param {boolean} [fromRight] Specify iterating from right to left.
5705 * @returns {Function} Returns the new base function.
5706 */
5707function createBaseFor(fromRight) {
5708  return function(object, iteratee, keysFunc) {
5709    var iterable = toObject(object),
5710        props = keysFunc(object),
5711        length = props.length,
5712        index = fromRight ? length : -1;
5713
5714    while ((fromRight ? index-- : ++index < length)) {
5715      var key = props[index];
5716      if (iteratee(iterable[key], key, iterable) === false) {
5717        break;
5718      }
5719    }
5720    return object;
5721  };
5722}
5723
5724module.exports = createBaseFor;
5725
5726},{"./toObject":47}],38:[function(require,module,exports){
5727var baseProperty = require('./baseProperty');
5728
5729/**
5730 * Gets the "length" property value of `object`.
5731 *
5732 * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
5733 * that affects Safari on at least iOS 8.1-8.3 ARM64.
5734 *
5735 * @private
5736 * @param {Object} object The object to query.
5737 * @returns {*} Returns the "length" value.
5738 */
5739var getLength = baseProperty('length');
5740
5741module.exports = getLength;
5742
5743},{"./baseProperty":34}],39:[function(require,module,exports){
5744var isNative = require('../lang/isNative');
5745
5746/**
5747 * Gets the native function at `key` of `object`.
5748 *
5749 * @private
5750 * @param {Object} object The object to query.
5751 * @param {string} key The key of the method to get.
5752 * @returns {*} Returns the function if it's native, else `undefined`.
5753 */
5754function getNative(object, key) {
5755  var value = object == null ? undefined : object[key];
5756  return isNative(value) ? value : undefined;
5757}
5758
5759module.exports = getNative;
5760
5761},{"../lang/isNative":51}],40:[function(require,module,exports){
5762var getLength = require('./getLength'),
5763    isLength = require('./isLength');
5764
5765/**
5766 * Checks if `value` is array-like.
5767 *
5768 * @private
5769 * @param {*} value The value to check.
5770 * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
5771 */
5772function isArrayLike(value) {
5773  return value != null && isLength(getLength(value));
5774}
5775
5776module.exports = isArrayLike;
5777
5778},{"./getLength":38,"./isLength":44}],41:[function(require,module,exports){
5779/**
5780 * Checks if `value` is a host object in IE < 9.
5781 *
5782 * @private
5783 * @param {*} value The value to check.
5784 * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
5785 */
5786var isHostObject = (function() {
5787  try {
5788    Object({ 'toString': 0 } + '');
5789  } catch(e) {
5790    return function() { return false; };
5791  }
5792  return function(value) {
5793    // IE < 9 presents many host objects as `Object` objects that can coerce
5794    // to strings despite having improperly defined `toString` methods.
5795    return typeof value.toString != 'function' && typeof (value + '') == 'string';
5796  };
5797}());
5798
5799module.exports = isHostObject;
5800
5801},{}],42:[function(require,module,exports){
5802/** Used to detect unsigned integer values. */
5803var reIsUint = /^\d+$/;
5804
5805/**
5806 * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
5807 * of an array-like value.
5808 */
5809var MAX_SAFE_INTEGER = 9007199254740991;
5810
5811/**
5812 * Checks if `value` is a valid array-like index.
5813 *
5814 * @private
5815 * @param {*} value The value to check.
5816 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
5817 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
5818 */
5819function isIndex(value, length) {
5820  value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
5821  length = length == null ? MAX_SAFE_INTEGER : length;
5822  return value > -1 && value % 1 == 0 && value < length;
5823}
5824
5825module.exports = isIndex;
5826
5827},{}],43:[function(require,module,exports){
5828var isArrayLike = require('./isArrayLike'),
5829    isIndex = require('./isIndex'),
5830    isObject = require('../lang/isObject');
5831
5832/**
5833 * Checks if the provided arguments are from an iteratee call.
5834 *
5835 * @private
5836 * @param {*} value The potential iteratee value argument.
5837 * @param {*} index The potential iteratee index or key argument.
5838 * @param {*} object The potential iteratee object argument.
5839 * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
5840 */
5841function isIterateeCall(value, index, object) {
5842  if (!isObject(object)) {
5843    return false;
5844  }
5845  var type = typeof index;
5846  if (type == 'number'
5847      ? (isArrayLike(object) && isIndex(index, object.length))
5848      : (type == 'string' && index in object)) {
5849    var other = object[index];
5850    return value === value ? (value === other) : (other !== other);
5851  }
5852  return false;
5853}
5854
5855module.exports = isIterateeCall;
5856
5857},{"../lang/isObject":52,"./isArrayLike":40,"./isIndex":42}],44:[function(require,module,exports){
5858/**
5859 * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
5860 * of an array-like value.
5861 */
5862var MAX_SAFE_INTEGER = 9007199254740991;
5863
5864/**
5865 * Checks if `value` is a valid array-like length.
5866 *
5867 * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
5868 *
5869 * @private
5870 * @param {*} value The value to check.
5871 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
5872 */
5873function isLength(value) {
5874  return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
5875}
5876
5877module.exports = isLength;
5878
5879},{}],45:[function(require,module,exports){
5880/**
5881 * Checks if `value` is object-like.
5882 *
5883 * @private
5884 * @param {*} value The value to check.
5885 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
5886 */
5887function isObjectLike(value) {
5888  return !!value && typeof value == 'object';
5889}
5890
5891module.exports = isObjectLike;
5892
5893},{}],46:[function(require,module,exports){
5894var isArguments = require('../lang/isArguments'),
5895    isArray = require('../lang/isArray'),
5896    isIndex = require('./isIndex'),
5897    isLength = require('./isLength'),
5898    isString = require('../lang/isString'),
5899    keysIn = require('../object/keysIn');
5900
5901/** Used for native method references. */
5902var objectProto = Object.prototype;
5903
5904/** Used to check objects for own properties. */
5905var hasOwnProperty = objectProto.hasOwnProperty;
5906
5907/**
5908 * A fallback implementation of `Object.keys` which creates an array of the
5909 * own enumerable property names of `object`.
5910 *
5911 * @private
5912 * @param {Object} object The object to query.
5913 * @returns {Array} Returns the array of property names.
5914 */
5915function shimKeys(object) {
5916  var props = keysIn(object),
5917      propsLength = props.length,
5918      length = propsLength && object.length;
5919
5920  var allowIndexes = !!length && isLength(length) &&
5921    (isArray(object) || isArguments(object) || isString(object));
5922
5923  var index = -1,
5924      result = [];
5925
5926  while (++index < propsLength) {
5927    var key = props[index];
5928    if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
5929      result.push(key);
5930    }
5931  }
5932  return result;
5933}
5934
5935module.exports = shimKeys;
5936
5937},{"../lang/isArguments":48,"../lang/isArray":49,"../lang/isString":54,"../object/keysIn":58,"./isIndex":42,"./isLength":44}],47:[function(require,module,exports){
5938var isObject = require('../lang/isObject'),
5939    isString = require('../lang/isString'),
5940    support = require('../support');
5941
5942/**
5943 * Converts `value` to an object if it's not one.
5944 *
5945 * @private
5946 * @param {*} value The value to process.
5947 * @returns {Object} Returns the object.
5948 */
5949function toObject(value) {
5950  if (support.unindexedChars && isString(value)) {
5951    var index = -1,
5952        length = value.length,
5953        result = Object(value);
5954
5955    while (++index < length) {
5956      result[index] = value.charAt(index);
5957    }
5958    return result;
5959  }
5960  return isObject(value) ? value : Object(value);
5961}
5962
5963module.exports = toObject;
5964
5965},{"../lang/isObject":52,"../lang/isString":54,"../support":60}],48:[function(require,module,exports){
5966var isArrayLike = require('../internal/isArrayLike'),
5967    isObjectLike = require('../internal/isObjectLike');
5968
5969/** Used for native method references. */
5970var objectProto = Object.prototype;
5971
5972/** Used to check objects for own properties. */
5973var hasOwnProperty = objectProto.hasOwnProperty;
5974
5975/** Native method references. */
5976var propertyIsEnumerable = objectProto.propertyIsEnumerable;
5977
5978/**
5979 * Checks if `value` is classified as an `arguments` object.
5980 *
5981 * @static
5982 * @memberOf _
5983 * @category Lang
5984 * @param {*} value The value to check.
5985 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
5986 * @example
5987 *
5988 * _.isArguments(function() { return arguments; }());
5989 * // => true
5990 *
5991 * _.isArguments([1, 2, 3]);
5992 * // => false
5993 */
5994function isArguments(value) {
5995  return isObjectLike(value) && isArrayLike(value) &&
5996    hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');
5997}
5998
5999module.exports = isArguments;
6000
6001},{"../internal/isArrayLike":40,"../internal/isObjectLike":45}],49:[function(require,module,exports){
6002var getNative = require('../internal/getNative'),
6003    isLength = require('../internal/isLength'),
6004    isObjectLike = require('../internal/isObjectLike');
6005
6006/** `Object#toString` result references. */
6007var arrayTag = '[object Array]';
6008
6009/** Used for native method references. */
6010var objectProto = Object.prototype;
6011
6012/**
6013 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
6014 * of values.
6015 */
6016var objToString = objectProto.toString;
6017
6018/* Native method references for those with the same name as other `lodash` methods. */
6019var nativeIsArray = getNative(Array, 'isArray');
6020
6021/**
6022 * Checks if `value` is classified as an `Array` object.
6023 *
6024 * @static
6025 * @memberOf _
6026 * @category Lang
6027 * @param {*} value The value to check.
6028 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
6029 * @example
6030 *
6031 * _.isArray([1, 2, 3]);
6032 * // => true
6033 *
6034 * _.isArray(function() { return arguments; }());
6035 * // => false
6036 */
6037var isArray = nativeIsArray || function(value) {
6038  return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
6039};
6040
6041module.exports = isArray;
6042
6043},{"../internal/getNative":39,"../internal/isLength":44,"../internal/isObjectLike":45}],50:[function(require,module,exports){
6044var isObject = require('./isObject');
6045
6046/** `Object#toString` result references. */
6047var funcTag = '[object Function]';
6048
6049/** Used for native method references. */
6050var objectProto = Object.prototype;
6051
6052/**
6053 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
6054 * of values.
6055 */
6056var objToString = objectProto.toString;
6057
6058/**
6059 * Checks if `value` is classified as a `Function` object.
6060 *
6061 * @static
6062 * @memberOf _
6063 * @category Lang
6064 * @param {*} value The value to check.
6065 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
6066 * @example
6067 *
6068 * _.isFunction(_);
6069 * // => true
6070 *
6071 * _.isFunction(/abc/);
6072 * // => false
6073 */
6074function isFunction(value) {
6075  // The use of `Object#toString` avoids issues with the `typeof` operator
6076  // in older versions of Chrome and Safari which return 'function' for regexes
6077  // and Safari 8 which returns 'object' for typed array constructors.
6078  return isObject(value) && objToString.call(value) == funcTag;
6079}
6080
6081module.exports = isFunction;
6082
6083},{"./isObject":52}],51:[function(require,module,exports){
6084var isFunction = require('./isFunction'),
6085    isHostObject = require('../internal/isHostObject'),
6086    isObjectLike = require('../internal/isObjectLike');
6087
6088/** Used to detect host constructors (Safari > 5). */
6089var reIsHostCtor = /^\[object .+?Constructor\]$/;
6090
6091/** Used for native method references. */
6092var objectProto = Object.prototype;
6093
6094/** Used to resolve the decompiled source of functions. */
6095var fnToString = Function.prototype.toString;
6096
6097/** Used to check objects for own properties. */
6098var hasOwnProperty = objectProto.hasOwnProperty;
6099
6100/** Used to detect if a method is native. */
6101var reIsNative = RegExp('^' +
6102  fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
6103  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
6104);
6105
6106/**
6107 * Checks if `value` is a native function.
6108 *
6109 * @static
6110 * @memberOf _
6111 * @category Lang
6112 * @param {*} value The value to check.
6113 * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
6114 * @example
6115 *
6116 * _.isNative(Array.prototype.push);
6117 * // => true
6118 *
6119 * _.isNative(_);
6120 * // => false
6121 */
6122function isNative(value) {
6123  if (value == null) {
6124    return false;
6125  }
6126  if (isFunction(value)) {
6127    return reIsNative.test(fnToString.call(value));
6128  }
6129  return isObjectLike(value) && (isHostObject(value) ? reIsNative : reIsHostCtor).test(value);
6130}
6131
6132module.exports = isNative;
6133
6134},{"../internal/isHostObject":41,"../internal/isObjectLike":45,"./isFunction":50}],52:[function(require,module,exports){
6135/**
6136 * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
6137 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
6138 *
6139 * @static
6140 * @memberOf _
6141 * @category Lang
6142 * @param {*} value The value to check.
6143 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
6144 * @example
6145 *
6146 * _.isObject({});
6147 * // => true
6148 *
6149 * _.isObject([1, 2, 3]);
6150 * // => true
6151 *
6152 * _.isObject(1);
6153 * // => false
6154 */
6155function isObject(value) {
6156  // Avoid a V8 JIT bug in Chrome 19-20.
6157  // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
6158  var type = typeof value;
6159  return !!value && (type == 'object' || type == 'function');
6160}
6161
6162module.exports = isObject;
6163
6164},{}],53:[function(require,module,exports){
6165var baseForIn = require('../internal/baseForIn'),
6166    isArguments = require('./isArguments'),
6167    isHostObject = require('../internal/isHostObject'),
6168    isObjectLike = require('../internal/isObjectLike'),
6169    support = require('../support');
6170
6171/** `Object#toString` result references. */
6172var objectTag = '[object Object]';
6173
6174/** Used for native method references. */
6175var objectProto = Object.prototype;
6176
6177/** Used to check objects for own properties. */
6178var hasOwnProperty = objectProto.hasOwnProperty;
6179
6180/**
6181 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
6182 * of values.
6183 */
6184var objToString = objectProto.toString;
6185
6186/**
6187 * Checks if `value` is a plain object, that is, an object created by the
6188 * `Object` constructor or one with a `[[Prototype]]` of `null`.
6189 *
6190 * **Note:** This method assumes objects created by the `Object` constructor
6191 * have no inherited enumerable properties.
6192 *
6193 * @static
6194 * @memberOf _
6195 * @category Lang
6196 * @param {*} value The value to check.
6197 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
6198 * @example
6199 *
6200 * function Foo() {
6201 *   this.a = 1;
6202 * }
6203 *
6204 * _.isPlainObject(new Foo);
6205 * // => false
6206 *
6207 * _.isPlainObject([1, 2, 3]);
6208 * // => false
6209 *
6210 * _.isPlainObject({ 'x': 0, 'y': 0 });
6211 * // => true
6212 *
6213 * _.isPlainObject(Object.create(null));
6214 * // => true
6215 */
6216function isPlainObject(value) {
6217  var Ctor;
6218
6219  // Exit early for non `Object` objects.
6220  if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isHostOb
6220ject(value) && !isArguments(value)) ||
6221      (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
6222    return false;
6223  }
6224  // IE < 9 iterates inherited properties before own properties. If the first
6225  // iterated property is an object's own property then there are no inherited
6226  // enumerable properties.
6227  var result;
6228  if (support.ownLast) {
6229    baseForIn(value, function(subValue, key, object) {
6230      result = hasOwnProperty.call(object, key);
6231      return false;
6232    });
6233    return result !== false;
6234  }
6235  // In most environments an object's own properties are iterated before
6236  // its inherited properties. If the last iterated property is an object's
6237  // own property then there are no inherited enumerable properties.
6238  baseForIn(value, function(subValue, key) {
6239    result = key;
6240  });
6241  return result === undefined || hasOwnProperty.call(value, result);
6242}
6243
6244module.exports = isPlainObject;
6245
6246},{"../internal/baseForIn":31,"../internal/isHostObject":41,"../internal/isObjectLike":45,"../support":60,"./isArguments":48}],54:[function(require,module,exports){
6247var isObjectLike = require('../internal/isObjectLike');
6248
6249/** `Object#toString` result references. */
6250var stringTag = '[object String]';
6251
6252/** Used for native method references. */
6253var objectProto = Object.prototype;
6254
6255/**
6256 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
6257 * of values.
6258 */
6259var objToString = objectProto.toString;
6260
6261/**
6262 * Checks if `value` is classified as a `String` primitive or object.
6263 *
6264 * @static
6265 * @memberOf _
6266 * @category Lang
6267 * @param {*} value The value to check.
6268 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
6269 * @example
6270 *
6271 * _.isString('abc');
6272 * // => true
6273 *
6274 * _.isString(1);
6275 * // => false
6276 */
6277function isString(value) {
6278  return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);
6279}
6280
6281module.exports = isString;
6282
6283},{"../internal/isObjectLike":45}],55:[function(require,module,exports){
6284var isLength = require('../internal/isLength'),
6285    isObjectLike = require('../internal/isObjectLike');
6286
6287/** `Object#toString` result references. */
6288var argsTag = '[object Arguments]',
6289    arrayTag = '[object Array]',
6290    boolTag = '[object Boolean]',
6291    dateTag = '[object Date]',
6292    errorTag = '[object Error]',
6293    funcTag = '[object Function]',
6294    mapTag = '[object Map]',
6295    numberTag = '[object Number]',
6296    objectTag = '[object Object]',
6297    regexpTag = '[object RegExp]',
6298    setTag = '[object Set]',
6299    stringTag = '[object String]',
6300    weakMapTag = '[object WeakMap]';
6301
6302var arrayBufferTag = '[object ArrayBuffer]',
6303    float32Tag = '[object Float32Array]',
6304    float64Tag = '[object Float64Array]',
6305    int8Tag = '[object Int8Array]',
6306    int16Tag = '[object Int16Array]',
6307    int32Tag = '[object Int32Array]',
6308    uint8Tag = '[object Uint8Array]',
6309    uint8ClampedTag = '[object Uint8ClampedArray]',
6310    uint16Tag = '[object Uint16Array]',
6311    uint32Tag = '[object Uint32Array]';
6312
6313/** Used to identify `toStringTag` values of typed arrays. */
6314var typedArrayTags = {};
6315typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
6316typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
6317typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
6318typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
6319typedArrayTags[uint32Tag] = true;
6320typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
6321typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
6322typedArrayTags[dateTag] = typedArrayTags[errorTag] =
6323typedArrayTags[funcTag] = typedArrayTags[mapTag] =
6324typedArrayTags[numberTag] = typedArrayTags[objectTag] =
6325typedArrayTags[regexpTag] = typedArrayTags[setTag] =
6326typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
6327
6328/** Used for native method references. */
6329var objectProto = Object.prototype;
6330
6331/**
6332 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
6333 * of values.
6334 */
6335var objToString = objectProto.toString;
6336
6337/**
6338 * Checks if `value` is classified as a typed array.
6339 *
6340 * @static
6341 * @memberOf _
6342 * @category Lang
6343 * @param {*} value The value to check.
6344 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
6345 * @example
6346 *
6347 * _.isTypedArray(new Uint8Array);
6348 * // => true
6349 *
6350 * _.isTypedArray([]);
6351 * // => false
6352 */
6353function isTypedArray(value) {
6354  return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
6355}
6356
6357module.exports = isTypedArray;
6358
6359},{"../internal/isLength":44,"../internal/isObjectLike":45}],56:[function(require,module,exports){
6360var baseCopy = require('../internal/baseCopy'),
6361    keysIn = require('../object/keysIn');
6362
6363/**
6364 * Converts `value` to a plain object flattening inherited enumerable
6365 * properties of `value` to own properties of the plain object.
6366 *
6367 * @static
6368 * @memberOf _
6369 * @category Lang
6370 * @param {*} value The value to convert.
6371 * @returns {Object} Returns the converted plain object.
6372 * @example
6373 *
6374 * function Foo() {
6375 *   this.b = 2;
6376 * }
6377 *
6378 * Foo.prototype.c = 3;
6379 *
6380 * _.assign({ 'a': 1 }, new Foo);
6381 * // => { 'a': 1, 'b': 2 }
6382 *
6383 * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
6384 * // => { 'a': 1, 'b': 2, 'c': 3 }
6385 */
6386function toPlainObject(value) {
6387  return baseCopy(value, keysIn(value));
6388}
6389
6390module.exports = toPlainObject;
6391
6392},{"../internal/baseCopy":29,"../object/keysIn":58}],57:[function(require,module,exports){
6393var getNative = require('../internal/getNative'),
6394    isArrayLike = require('../internal/isArrayLike'),
6395    isObject = require('../lang/isObject'),
6396    shimKeys = require('../internal/shimKeys'),
6397    support = require('../support');
6398
6399/* Native method references for those with the same name as other `lodash` methods. */
6400var nativeKeys = getNative(Object, 'keys');
6401
6402/**
6403 * Creates an array of the own enumerable property names of `object`.
6404 *
6405 * **Note:** Non-object values are coerced to objects. See the
6406 * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
6407 * for more details.
6408 *
6409 * @static
6410 * @memberOf _
6411 * @category Object
6412 * @param {Object} object The object to query.
6413 * @returns {Array} Returns the array of property names.
6414 * @example
6415 *
6416 * function Foo() {
6417 *   this.a = 1;
6418 *   this.b = 2;
6419 * }
6420 *
6421 * Foo.prototype.c = 3;
6422 *
6423 * _.keys(new Foo);
6424 * // => ['a', 'b'] (iteration order is not guaranteed)
6425 *
6426 * _.keys('hi');
6427 * // => ['0', '1']
6428 */
6429var keys = !nativeKeys ? shimKeys : function(object) {
6430  var Ctor = object == null ? undefined : object.constructor;
6431  if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
6432      (typeof object == 'function' ? support.enumPrototypes : isArrayLike(object))) {
6433    return shimKeys(object);
6434  }
6435  return isObject(object) ? nativeKeys(object) : [];
6436};
6437
6438module.exports = keys;
6439
6440},{"../internal/getNative":39,"../internal/isArrayLike":40,"../internal/shimKeys":46,"../lang/isObject":52,"../support":60}],58:[function(require,module,exports){
6441var arrayEach = require('../internal/arrayEach'),
6442    isArguments = require('../lang/isArguments'),
6443    isArray = require('../lang/isArray'),
6444    isFunction = require('../lang/isFunction'),
6445    isIndex = require('../internal/isIndex'),
6446    isLength = require('../internal/isLength'),
6447    isObject = require('../lang/isObject'),
6448    isString = require('../lang/isString'),
6449    support = require('../support');
6450
6451/** `Object#toString` result references. */
6452var arrayTag = '[object Array]',
6453    boolTag = '[object Boolean]',
6454    dateTag = '[object Date]',
6455    errorTag = '[object Error]',
6456    funcTag = '[object Function]',
6457    numberTag = '[object Number]',
6458    objectTag = '[object Object]',
6459    regexpTag = '[object RegExp]',
6460    stringTag = '[object String]';
6461
6462/** Used to fix the JScript `[[DontEnum]]` bug. */
6463var shadowProps = [
6464  'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
6465  'toLocaleString', 'toString', 'valueOf'
6466];
6467
6468/** Used for native method references. */
6469var errorProto = Error.prototype,
6470    objectProto = Object.prototype,
6471    stringProto = String.prototype;
6472
6473/** Used to check objects for own properties. */
6474var hasOwnProperty = objectProto.hasOwnProperty;
6475
6476/**
6477 * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
6478 * of values.
6479 */
6480var objToString = objectProto.toString;
6481
6482/** Used to avoid iterating over non-enumerable properties in IE < 9. */
6483var nonEnumProps = {};
6484nonEnumProps[arrayTag] = nonEnumProps[dateTag] = nonEnumProps[numberTag] = { 'constructor': true, 'toLocaleStr
6484ing': true, 'toString': true, 'valueOf': true };
6485nonEnumProps[boolTag] = nonEnumProps[stringTag] = { 'constructor': true, 'toString': true, 'valueOf': true };
6486nonEnumProps[errorTag] = nonEnumProps[funcTag] = nonEnumProps[regexpTag] = { 'constructor': true, 'toString': true };
6487nonEnumProps[objectTag] = { 'constructor': true };
6488
6489arrayEach(shadowProps, function(key) {
6490  for (var tag in nonEnumProps) {
6491    if (hasOwnProperty.call(nonEnumProps, tag)) {
6492      var props = nonEnumProps[tag];
6493      props[key] = hasOwnProperty.call(props, key);
6494    }
6495  }
6496});
6497
6498/**
6499 * Creates an array of the own and inherited enumerable property names of `object`.
6500 *
6501 * **Note:** Non-object values are coerced to objects.
6502 *
6503 * @static
6504 * @memberOf _
6505 * @category Object
6506 * @param {Object} object The object to query.
6507 * @returns {Array} Returns the array of property names.
6508 * @example
6509 *
6510 * function Foo() {
6511 *   this.a = 1;
6512 *   this.b = 2;
6513 * }
6514 *
6515 * Foo.prototype.c = 3;
6516 *
6517 * _.keysIn(new Foo);
6518 * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
6519 */
6520function keysIn(object) {
6521  if (object == null) {
6522    return [];
6523  }
6524  if (!isObject(object)) {
6525    object = Object(object);
6526  }
6527  var length = object.length;
6528
6529  length = (length && isLength(length) &&
6530    (isArray(object) || isArguments(object) || isString(object)) && length) || 0;
6531
6532  var Ctor = object.constructor,
6533      index = -1,
6534      proto = (isFunction(Ctor) && Ctor.prototype) || objectProto,
6535      isProto = proto === object,
6536      result = Array(length),
6537      skipIndexes = length > 0,
6538      skipErrorProps = support.enumErrorProps && (object === errorProto || object instanceof Error),
6539      skipProto = support.enumPrototypes && isFunction(object);
6540
6541  while (++index < length) {
6542    result[index] = (index + '');
6543  }
6544  // lodash skips the `constructor` property when it infers it's iterating
6545  // over a `prototype` object because IE < 9 can't set the `[[Enumerable]]`
6546  // attribute of an existing property and the `constructor` property of a
6547  // prototype defaults to non-enumerable.
6548  for (var key in object) {
6549    if (!(skipProto && key == 'prototype') &&
6550        !(skipErrorProps && (key == 'message' || key == 'name')) &&
6551        !(skipIndexes && isIndex(key, length)) &&
6552        !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
6553      result.push(key);
6554    }
6555  }
6556  if (support.nonEnumShadows && object !== objectProto) {
6557    var tag = object === stringProto ? stringTag : (object === errorProto ? errorTag : objToString.call(object)),
6558        nonEnums = nonEnumProps[tag] || nonEnumProps[objectTag];
6559
6560    if (tag == objectTag) {
6561      proto = objectProto;
6562    }
6563    length = shadowProps.length;
6564    while (length--) {
6565      key = shadowProps[length];
6566      var nonEnum = nonEnums[key];
6567      if (!(isProto && nonEnum) &&
6568          (nonEnum ? hasOwnProperty.call(object, key) : object[key] !== proto[key])) {
6569        result.push(key);
6570      }
6571    }
6572  }
6573  return result;
6574}
6575
6576module.exports = keysIn;
6577
6578},{"../internal/arrayEach":28,"../internal/isIndex":42,"../internal/isLength":44,"../lang/isArguments":48,"../lang/isArray":49,"../lang/isFunction":50,"../lang/isObject":52,"../lang/isString":54,"../support":60}],59:[function(require,module,exports){
6579var baseMerge = require('../internal/baseMerge'),
6580    createAssigner = require('../internal/createAssigner');
6581
6582/**
6583 * Recursively merges own enumerable properties of the source object(s), that
6584 * don't resolve to `undefined` into the destination object. Subsequent sources
6585 * overwrite property assignments of previous sources. If `customizer` is
6586 * provided it's invoked to produce the merged values of the destination and
6587 * source properties. If `customizer` returns `undefined` merging is handled
6588 * by the method instead. The `customizer` is bound to `thisArg` and invoked
6589 * with five arguments: (objectValue, sourceValue, key, object, source).
6590 *
6591 * @static
6592 * @memberOf _
6593 * @category Object
6594 * @param {Object} object The destination object.
6595 * @param {...Object} [sources] The source objects.
6596 * @param {Function} [customizer] The function to customize assigned values.
6597 * @param {*} [thisArg] The `this` binding of `customizer`.
6598 * @returns {Object} Returns `object`.
6599 * @example
6600 *
6601 * var users = {
6602 *   'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
6603 * };
6604 *
6605 * var ages = {
6606 *   'data': [{ 'age': 36 }, { 'age': 40 }]
6607 * };
6608 *
6609 * _.merge(users, ages);
6610 * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
6611 *
6612 * // using a customizer callback
6613 * var object = {
6614 *   'fruits': ['apple'],
6615 *   'vegetables': ['beet']
6616 * };
6617 *
6618 * var other = {
6619 *   'fruits': ['banana'],
6620 *   'vegetables': ['carrot']
6621 * };
6622 *
6623 * _.merge(object, other, function(a, b) {
6624 *   if (_.isArray(a)) {
6625 *     return a.concat(b);
6626 *   }
6627 * });
6628 * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
6629 */
6630var merge = createAssigner(baseMerge);
6631
6632module.exports = merge;
6633
6634},{"../internal/baseMerge":32,"../internal/createAssigner":36}],60:[function(require,module,exports){
6635/** Used for native method references. */
6636var arrayProto = Array.prototype,
6637    errorProto = Error.prototype,
6638    objectProto = Object.prototype;
6639
6640/** Native method references. */
6641var propertyIsEnumerable = objectProto.propertyIsEnumerable,
6642    splice = arrayProto.splice;
6643
6644/**
6645 * An object environment feature flags.
6646 *
6647 * @static
6648 * @memberOf _
6649 * @type Object
6650 */
6651var support = {};
6652
6653(function(x) {
6654  var Ctor = function() { this.x = x; },
6655      object = { '0': x, 'length': x },
6656      props = [];
6657
6658  Ctor.prototype = { 'valueOf': x, 'y': x };
6659  for (var key in new Ctor) { props.push(key); }
6660
6661  /**
6662   * Detect if `name` or `message` properties of `Error.prototype` are
6663   * enumerable by default (IE < 9, Safari < 5.1).
6664   *
6665   * @memberOf _.support
6666   * @type boolean
6667   */
6668  support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') ||
6669    propertyIsEnumerable.call(errorProto, 'name');
6670
6671  /**
6672   * Detect if `prototype` properties are enumerable by default.
6673   *
6674   * Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
6675   * (if the prototype or a property on the prototype has been set)
6676   * incorrectly set the `[[Enumerable]]` value of a function's `prototype`
6677   * property to `true`.
6678   *
6679   * @memberOf _.support
6680   * @type boolean
6681   */
6682  support.enumPrototypes = propertyIsEnumerable.call(Ctor, 'prototype');
6683
6684  /**
6685   * Detect if properties shadowing those on `Object.prototype` are non-enumerable.
6686   *
6687   * In IE < 9 an object's own properties, shadowing non-enumerable ones,
6688   * are made non-enumerable as well (a.k.a the JScript `[[DontEnum]]` bug).
6689   *
6690   * @memberOf _.support
6691   * @type boolean
6692   */
6693  support.nonEnumShadows = !/valueOf/.test(props);
6694
6695  /**
6696   * Detect if own properties are iterated after inherited properties (IE < 9).
6697   *
6698   * @memberOf _.support
6699   * @type boolean
6700   */
6701  support.ownLast = props[0] != 'x';
6702
6703  /**
6704   * Detect if `Array#shift` and `Array#splice` augment array-like objects
6705   * correctly.
6706   *
6707   * Firefox < 10, compatibility modes of IE 8, and IE < 9 have buggy Array
6708   * `shift()` and `splice()` functions that fail to remove the last element,
6709   * `value[0]`, of array-like objects even though the "length" property is
6710   * set to `0`. The `shift()` method is buggy in compatibility modes of IE 8,
6711   * while `splice()` is buggy regardless of mode in IE < 9.
6712   *
6713   * @memberOf _.support
6714   * @type boolean
6715   */
6716  support.spliceObjects = (splice.call(object, 0, 1), !object[0]);
6717
6718  /**
6719   * Detect lack of support for accessing string characters by index.
6720   *
6721   * IE < 8 can't access characters by index. IE 8 can only access characters
6722   * by index on string literals, not string objects.
6723   *
6724   * @memberOf _.support
6725   * @type boolean
6726   */
6727  support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx';
6728}(1, 0));
6729
6730module.exports = support;
6731
6732},{}],61:[function(require,module,exports){
6733/**
6734 * This method returns the first argument provided to it.
6735 *
6736 * @static
6737 * @memberOf _
6738 * @category Utility
6739 * @param {*} value Any value.
6740 * @returns {*} Returns `value`.
6741 * @example
6742 *
6743 * var object = { 'user': 'fred' };
6744 *
6745 * _.identity(object) === object;
6746 * // => true
6747 */
6748function identity(value) {
6749  return value;
6750}
6751
6752module.exports = identity;
6753
6754},{}],62:[function(require,module,exports){
6755/**
6756 * @file m3u8/index.js
6757 *
6758 * Utilities for parsing M3U8 files. If the entire manifest is available,
6759 * `Parser` will create an object representation with enough detail for managing
6760 * playback. `ParseStream` and `LineStream` are lower-level parsing primitives
6761 * that do not assume the entirety of the manifest is ready and expose a
6762 * ReadableStream-like interface.
6763 */
6764
6765'use strict';
6766
6767Object.defineProperty(exports, '__esModule', {
6768  value: true
6769});
6770
6771function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6772
6773var _lineStream = require('./line-stream');
6774
6775var _lineStream2 = _interopRequireDefault(_lineStream);
6776
6777var _parseStream = require('./parse-stream');
6778
6779var _parseStream2 = _interopRequireDefault(_parseStream);
6780
6781var _parser = require('./parser');
6782
6783var _parser2 = _interopRequireDefault(_parser);
6784
6785exports['default'] = {
6786  LineStream: _lineStream2['default'],
6787  ParseStream: _parseStream2['default'],
6788  Parser: _parser2['default']
6789};
6790module.exports = exports['default'];
6791},{"./line-stream":63,"./parse-stream":64,"./parser":65}],63:[function(require,module,exports){
6792/**
6793 * @file m3u8/line-stream.js
6794 */
6795'use strict';
6796
6797Object.defineProperty(exports, '__esModule', {
6798  value: true
6799});
6800
6801var _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; }; })();
6802
6803var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
6804
6805function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6806
6807function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
6808
6809function _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, { c
6809onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
6810
6811var _stream = require('./stream');
6812
6813var _stream2 = _interopRequireDefault(_stream);
6814
6815/**
6816 * A stream that buffers string input and generates a `data` event for each
6817 * line.
6818 *
6819 * @class LineStream
6820 * @extends Stream
6821 */
6822
6823var LineStream = (function (_Stream) {
6824  _inherits(LineStream, _Stream);
6825
6826  function LineStream() {
6827    _classCallCheck(this, LineStream);
6828
6829    _get(Object.getPrototypeOf(LineStream.prototype), 'constructor', this).call(this);
6830    this.buffer = '';
6831  }
6832
6833  /**
6834   * Add new data to be parsed.
6835   *
6836   * @param {String} data the text to process
6837   */
6838
6839  _createClass(LineStream, [{
6840    key: 'push',
6841    value: function push(data) {
6842      var nextNewline = undefined;
6843
6844      this.buffer += data;
6845      nextNewline = this.buffer.indexOf('\n');
6846
6847      for (; nextNewline > -1; nextNewline = this.buffer.indexOf('\n')) {
6848        this.trigger('data', this.buffer.substring(0, nextNewline));
6849        this.buffer = this.buffer.substring(nextNewline + 1);
6850      }
6851    }
6852  }]);
6853
6854  return LineStream;
6855})(_stream2['default']);
6856
6857exports['default'] = LineStream;
6858module.exports = exports['default'];
6859},{"./stream":66}],64:[function(require,module,exports){
6860/**
6861 * @file m3u8/parse-stream.js
6862 */
6863'use strict';
6864
6865Object.defineProperty(exports, '__esModule', {
6866  value: true
6867});
6868
6869var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
6870
6871var _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; }; })();
6872
6873var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
6874
6875function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6876
6877function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
6878
6879function _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; }
6880
6881var _stream = require('./stream');
6882
6883var _stream2 = _interopRequireDefault(_stream);
6884
6885/**
6886 * "forgiving" attribute list psuedo-grammar:
6887 * attributes -> keyvalue (',' keyvalue)*
6888 * keyvalue   -> key '=' value
6889 * key        -> [^=]*
6890 * value      -> '"' [^"]* '"' | [^,]*
6891 */
6892var attributeSeparator = function attributeSeparator() {
6893  var key = '[^=]*';
6894  var value = '"[^"]*"|[^,]*';
6895  var keyvalue = '(?:' + key + ')=(?:' + value + ')';
6896
6897  return new RegExp('(?:^|,)(' + keyvalue + ')');
6898};
6899
6900/**
6901 * Parse attributes from a line given the seperator
6902 *
6903 * @param {String} attributes the attibute line to parse
6904 */
6905var parseAttributes = function parseAttributes(attributes) {
6906  // split the string using attributes as the separator
6907  var attrs = attributes.split(attributeSeparator());
6908  var i = attrs.length;
6909  var result = {};
6910  var attr = undefined;
6911
6912  while (i--) {
6913    // filter out unmatched portions of the string
6914    if (attrs[i] === '') {
6915      continue;
6916    }
6917
6918    // split the key and value
6919    attr = /([^=]*)=(.*)/.exec(attrs[i]).slice(1);
6920    // trim whitespace and remove optional quotes around the value
6921    attr[0] = attr[0].replace(/^\s+|\s+$/g, '');
6922    attr[1] = attr[1].replace(/^\s+|\s+$/g, '');
6923    attr[1] = attr[1].replace(/^['"](.*)['"]$/g, '$1');
6924    result[attr[0]] = attr[1];
6925  }
6926  return result;
6927};
6928
6929/**
6930 * A line-level M3U8 parser event stream. It expects to receive input one
6931 * line at a time and performs a context-free parse of its contents. A stream
6932 * interpretation of a manifest can be useful if the manifest is expected to
6933 * be too large to fit comfortably into memory or the entirety of the input
6934 * is not immediately available. Otherwise, it's probably much easier to work
6935 * with a regular `Parser` object.
6936 *
6937 * Produces `data` events with an object that captures the parser's
6938 * interpretation of the input. That object has a property `tag` that is one
6939 * of `uri`, `comment`, or `tag`. URIs only have a single additional
6940 * property, `line`, which captures the entirety of the input without
6941 * interpretation. Comments similarly have a single additional property
6942 * `text` which is the input without the leading `#`.
6943 *
6944 * Tags always have a property `tagType` which is the lower-cased version of
6945 * the M3U8 directive without the `#EXT` or `#EXT-X-` prefix. For instance,
6946 * `#EXT-X-MEDIA-SEQUENCE` becomes `media-sequence` when parsed. Unrecognized
6947 * tags are given the tag type `unknown` and a single additional property
6948 * `data` with the remainder of the input.
6949 *
6950 * @class ParseStream
6951 * @extends Stream
6952 */
6953
6954var ParseStream = (function (_Stream) {
6955  _inherits(ParseStream, _Stream);
6956
6957  function ParseStream() {
6958    _classCallCheck(this, ParseStream);
6959
6960    _get(Object.getPrototypeOf(ParseStream.prototype), 'constructor', this).call(this);
6961  }
6962
6963  /**
6964   * Parses an additional line of input.
6965   *
6966   * @param {String} line a single line of an M3U8 file to parse
6967   */
6968
6969  _createClass(ParseStream, [{
6970    key: 'push',
6971    value: function push(line) {
6972      var match = undefined;
6973      var event = undefined;
6974
6975      // strip whitespace
6976      line = line.replace(/^[\u0000\s]+|[\u0000\s]+$/g, '');
6977      if (line.length === 0) {
6978        // ignore empty lines
6979        return;
6980      }
6981
6982      // URIs
6983      if (line[0] !== '#') {
6984        this.trigger('data', {
6985          type: 'uri',
6986          uri: line
6987        });
6988        return;
6989      }
6990
6991      // Comments
6992      if (line.indexOf('#EXT') !== 0) {
6993        this.trigger('data', {
6994          type: 'comment',
6995          text: line.slice(1)
6996        });
6997        return;
6998      }
6999
7000      // strip off any carriage returns here so the regex matching
7001      // doesn't have to account for them.
7002      line = line.replace('\r', '');
7003
7004      // Tags
7005      match = /^#EXTM3U/.exec(line);
7006      if (match) {
7007        this.trigger('data', {
7008          type: 'tag',
7009          tagType: 'm3u'
7010        });
7011        return;
7012      }
7013      match = /^#EXTINF:?([0-9\.]*)?,?(.*)?$/.exec(line);
7014      if (match) {
7015        event = {
7016          type: 'tag',
7017          tagType: 'inf'
7018        };
7019        if (match[1]) {
7020          event.duration = parseFloat(match[1]);
7021        }
7022        if (match[2]) {
7023          event.title = match[2];
7024        }
7025        this.trigger('data', event);
7026        return;
7027      }
7028      match = /^#EXT-X-TARGETDURATION:?([0-9.]*)?/.exec(line);
7029      if (match) {
7030        event = {
7031          type: 'tag',
7032          tagType: 'targetduration'
7033        };
7034        if (match[1]) {
7035          event.duration = parseInt(match[1], 10);
7036        }
7037        this.trigger('data', event);
7038        return;
7039      }
7040      match = /^#ZEN-TOTAL-DURATION:?([0-9.]*)?/.exec(line);
7041      if (match) {
7042        event = {
7043          type: 'tag',
7044          tagType: 'totalduration'
7045        };
7046        if (match[1]) {
7047          event.duration = parseInt(match[1], 10);
7048        }
7049        this.trigger('data', event);
7050        return;
7051      }
7052      match = /^#EXT-X-VERSION:?([0-9.]*)?/.exec(line);
7053      if (match) {
7054        event = {
7055          type: 'tag',
7056          tagType: 'version'
7057        };
7058        if (match[1]) {
7059          event.version = parseInt(match[1], 10);
7060        }
7061        this.trigger('data', event);
7062        return;
7063      }
7064      match = /^#EXT-X-MEDIA-SEQUENCE:?(\-?[0-9.]*)?/.exec(line);
7065      if (match) {
7066        event = {
7067          type: 'tag',
7068          tagType: 'media-sequence'
7069        };
7070        if (match[1]) {
7071          event.number = parseInt(match[1], 10);
7072        }
7073        this.trigger('data', event);
7074        return;
7075      }
7076      match = /^#EXT-X-DISCONTINUITY-SEQUENCE:?(\-?[0-9.]*)?/.exec(line);
7077      if (match) {
7078        event = {
7079          type: 'tag',
7080          tagType: 'discontinuity-sequence'
7081        };
7082        if (match[1]) {
7083          event.number = parseInt(match[1], 10);
7084        }
7085        this.trigger('data', event);
7086        return;
7087      }
7088      match = /^#EXT-X-PLAYLIST-TYPE:?(.*)?$/.exec(line);
7089      if (match) {
7090        event = {
7091          type: 'tag',
7092          tagType: 'playlist-type'
7093        };
7094        if (match[1]) {
7095          event.playlistType = match[1];
7096        }
7097        this.trigger('data', event);
7098        return;
7099      }
7100      match = /^#EXT-X-BYTERANGE:?([0-9.]*)?@?([0-9.]*)?/.exec(line);
7101      if (match) {
7102        event = {
7103          type: 'tag',
7104          tagType: 'byterange'
7105        };
7106        if (match[1]) {
7107          event.length = parseInt(match[1], 10);
7108        }
7109        if (match[2]) {
7110          event.offset = parseInt(match[2], 10);
7111        }
7112        this.trigger('data', event);
7113        return;
7114      }
7115      match = /^#EXT-X-ALLOW-CACHE:?(YES|NO)?/.exec(line);
7116      if (match) {
7117        event = {
7118          type: 'tag',
7119          tagType: 'allow-cache'
7120        };
7121        if (match[1]) {
7122          event.allowed = !/NO/.test(match[1]);
7123        }
7124        this.trigger('data', event);
7125        return;
7126      }
7127      match = /^#EXT-X-MAP:?(.*)$/.exec(line);
7128      if (match) {
7129        event = {
7130          type: 'tag',
7131          tagType: 'map'
7132        };
7133
7134        if (match[1]) {
7135          var attributes = parseAttributes(match[1]);
7136
7137          if (attributes.URI) {
7138            event.uri = attributes.URI;
7139          }
7140          if (attributes.BYTERANGE) {
7141            var _attributes$BYTERANGE$split = attributes.BYTERANGE.split('@');
7142
7143            var _attributes$BYTERANGE$split2 = _slicedToArray(_attributes$BYTERANGE$split, 2);
7144
7145            var _length = _attributes$BYTERANGE$split2[0];
7146            var offset = _attributes$BYTERANGE$split2[1];
7147
7148            event.byterange = {};
7149            if (_length) {
7150              event.byterange.length = parseInt(_length, 10);
7151            }
7152            if (offset) {
7153              event.byterange.offset = parseInt(offset, 10);
7154            }
7155          }
7156        }
7157
7158        this.trigger('data', event);
7159        return;
7160      }
7161      match = /^#EXT-X-STREAM-INF:?(.*)$/.exec(line);
7162      if (match) {
7163        event = {
7164          type: 'tag',
7165          tagType: 'stream-inf'
7166        };
7167        if (match[1]) {
7168          event.attributes = parseAttributes(match[1]);
7169
7170          if (event.attributes.RESOLUTION) {
7171            var split = event.attributes.RESOLUTION.split('x');
7172            var resolution = {};
7173
7174            if (split[0]) {
7175              resolution.width = parseInt(split[0], 10);
7176            }
7177            if (split[1]) {
7178              resolution.height = parseInt(split[1], 10);
7179            }
7180            event.attributes.RESOLUTION = resolution;
7181          }
7182          if (event.attributes.BANDWIDTH) {
7183            event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10);
7184          }
7185          if (event.attributes['PROGRAM-ID']) {
7186            event.attributes['PROGRAM-ID'] = parseInt(event.attributes['PROGRAM-ID'], 10);
7187          }
7188        }
7189        this.trigger('data', event);
7190        return;
7191      }
7192      match = /^#EXT-X-MEDIA:?(.*)$/.exec(line);
7193      if (match) {
7194        event = {
7195          type: 'tag',
7196          tagType: 'media'
7197        };
7198        if (match[1]) {
7199          event.attributes = parseAttributes(match[1]);
7200        }
7201        this.trigger('data', event);
7202        return;
7203      }
7204      match = /^#EXT-X-ENDLIST/.exec(line);
7205      if (match) {
7206        this.trigger('data', {
7207          type: 'tag',
7208          tagType: 'endlist'
7209        });
7210        return;
7211      }
7212      match = /^#EXT-X-DISCONTINUITY/.exec(line);
7213      if (match) {
7214        this.trigger('data', {
7215          type: 'tag',
7216          tagType: 'discontinuity'
7217        });
7218        return;
7219      }
7220      match = /^#EXT-X-PROGRAM-DATE-TIME:?(.*)$/.exec(line);
7221      if (match) {
7222        event = {
7223          type: 'tag',
7224          tagType: 'program-date-time'
7225        };
7226        if (match[1]) {
7227          event.dateTimeString = match[1];
7228          event.dateTimeObject = new Date(match[1]);
7229        }
7230        this.trigger('data', event);
7231        return;
7232      }
7233      match = /^#EXT-X-KEY:?(.*)$/.exec(line);
7234      if (match) {
7235        event = {
7236          type: 'tag',
7237          tagType: 'key'
7238        };
7239        if (match[1]) {
7240          event.attributes = parseAttributes(match[1]);
7241          // parse the IV string into a Uint32Array
7242          if (event.attributes.IV) {
7243            if (event.attributes.IV.substring(0, 2).toLowerCase() === '0x') {
7244              event.attributes.IV = event.attributes.IV.substring(2);
7245            }
7246
7247            event.attributes.IV = event.attributes.IV.match(/.{8}/g);
7248            event.attributes.IV[0] = parseInt(event.attributes.IV[0], 16);
7249            event.attributes.IV[1] = parseInt(event.attributes.IV[1], 16);
7250            event.attributes.IV[2] = parseInt(event.attributes.IV[2], 16);
7251            event.attributes.IV[3] = parseInt(event.attributes.IV[3], 16);
7252            event.attributes.IV = new Uint32Array(event.attributes.IV);
7253          }
7254        }
7255        this.trigger('data', event);
7256        return;
7257      }
7258      match = /^#EXT-X-CUE-OUT-CONT:?(.*)?$/.exec(line);
7259      if (match) {
7260        event = {
7261          type: 'tag',
7262          tagType: 'cue-out-cont'
7263        };
7264        if (match[1]) {
7265          event.data = match[1];
7266        } else {
7267          event.data = '';
7268        }
7269        this.trigger('data', event);
7270        return;
7271      }
7272      match = /^#EXT-X-CUE-OUT:?(.*)?$/.exec(line);
7273      if (match) {
7274        event = {
7275          type: 'tag',
7276          tagType: 'cue-out'
7277        };
7278        if (match[1]) {
7279          event.data = match[1];
7280        } else {
7281          event.data = '';
7282        }
7283        this.trigger('data', event);
7284        return;
7285      }
7286      match = /^#EXT-X-CUE-IN:?(.*)?$/.exec(line);
7287      if (match) {
7288        event = {
7289          type: 'tag',
7290          tagType: 'cue-in'
7291        };
7292        if (match[1]) {
7293          event.data = match[1];
7294        } else {
7295          event.data = '';
7296        }
7297        this.trigger('data', event);
7298        return;
7299      }
7300
7301      // unknown tag type
7302      this.trigger('data', {
7303        type: 'tag',
7304        data: line.slice(4)
7305      });
7306    }
7307  }]);
7308
7309  return ParseStream;
7310})(_stream2['default']);
7311
7312exports['default'] = ParseStream;
7313module.exports = exports['default'];
7314},{"./stream":66}],65:[function(require,module,exports){
7315/**
7316 * @file m3u8/parser.js
7317 */
7318'use strict';
7319
7320Object.defineProperty(exports, '__esModule', {
7321  value: true
7322});
7323
7324var _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; }; })();
7325
7326var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
7327
7328function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
7329
7330function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
7331
7332function _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, { c
vendor: 24,235 bytes, lines 7332-8119
7332onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
7333
7334var _stream = require('./stream');
7335
7336var _stream2 = _interopRequireDefault(_stream);
7337
7338var _lineStream = require('./line-stream');
7339
7340var _lineStream2 = _interopRequireDefault(_lineStream);
7341
7342var _parseStream = require('./parse-stream');
7343
7344var _parseStream2 = _interopRequireDefault(_parseStream);
7345
7346var _lodashCompatObjectMerge = require('lodash-compat/object/merge');
7347
7348var _lodashCompatObjectMerge2 = _interopRequireDefault(_lodashCompatObjectMerge);
7349
7350/**
7351 * A parser for M3U8 files. The current interpretation of the input is
7352 * exposed as a property `manifest` on parser objects. It's just two lines to
7353 * create and parse a manifest once you have the contents available as a string:
7354 *
7355 * ```js
7356 * var parser = new m3u8.Parser();
7357 * parser.push(xhr.responseText);
7358 * ```
7359 *
7360 * New input can later be applied to update the manifest object by calling
7361 * `push` again.
7362 *
7363 * The parser attempts to create a usable manifest object even if the
7364 * underlying input is somewhat nonsensical. It emits `info` and `warning`
7365 * events during the parse if it encounters input that seems invalid or
7366 * requires some property of the manifest object to be defaulted.
7367 *
7368 * @class Parser
7369 * @extends Stream
7370 */
7371
7372var Parser = (function (_Stream) {
7373  _inherits(Parser, _Stream);
7374
7375  function Parser() {
7376    _classCallCheck(this, Parser);
7377
7378    _get(Object.getPrototypeOf(Parser.prototype), 'constructor', this).call(this);
7379    this.lineStream = new _lineStream2['default']();
7380    this.parseStream = new _parseStream2['default']();
7381    this.lineStream.pipe(this.parseStream);
7382    /* eslint-disable consistent-this */
7383    var self = this;
7384    /* eslint-enable consistent-this */
7385    var uris = [];
7386    var currentUri = {};
7387    // if specified, the active EXT-X-MAP definition
7388    var currentMap = undefined;
7389    // if specified, the active decryption key
7390    var _key = undefined;
7391    var noop = function noop() {};
7392    var defaultMediaGroups = {
7393      'AUDIO': {},
7394      'VIDEO': {},
7395      'CLOSED-CAPTIONS': {},
7396      'SUBTITLES': {}
7397    };
7398    // group segments into numbered timelines delineated by discontinuities
7399    var currentTimeline = 0;
7400
7401    // the manifest is empty until the parse stream begins delivering data
7402    this.manifest = {
7403      allowCache: true,
7404      discontinuityStarts: []
7405    };
7406
7407    // update the manifest with the m3u8 entry from the parse stream
7408    this.parseStream.on('data', function (entry) {
7409      var mediaGroup = undefined;
7410      var rendition = undefined;
7411
7412      ({
7413        tag: function tag() {
7414          // switch based on the tag type
7415          (({
7416            'allow-cache': function allowCache() {
7417              this.manifest.allowCache = entry.allowed;
7418              if (!('allowed' in entry)) {
7419                this.trigger('info', {
7420                  message: 'defaulting allowCache to YES'
7421                });
7422                this.manifest.allowCache = true;
7423              }
7424            },
7425            byterange: function byterange() {
7426              var byterange = {};
7427
7428              if ('length' in entry) {
7429                currentUri.byterange = byterange;
7430                byterange.length = entry.length;
7431
7432                if (!('offset' in entry)) {
7433                  this.trigger('info', {
7434                    message: 'defaulting offset to zero'
7435                  });
7436                  entry.offset = 0;
7437                }
7438              }
7439              if ('offset' in entry) {
7440                currentUri.byterange = byterange;
7441                byterange.offset = entry.offset;
7442              }
7443            },
7444            endlist: function endlist() {
7445              this.manifest.endList = true;
7446            },
7447            inf: function inf() {
7448              if (!('mediaSequence' in this.manifest)) {
7449                this.manifest.mediaSequence = 0;
7450                this.trigger('info', {
7451                  message: 'defaulting media sequence to zero'
7452                });
7453              }
7454              if (!('discontinuitySequence' in this.manifest)) {
7455                this.manifest.discontinuitySequence = 0;
7456                this.trigger('info', {
7457                  message: 'defaulting discontinuity sequence to zero'
7458                });
7459              }
7460              if (entry.duration > 0) {
7461                currentUri.duration = entry.duration;
7462              }
7463
7464              if (entry.duration === 0) {
7465                currentUri.duration = 0.01;
7466                this.trigger('info', {
7467                  message: 'updating zero segment duration to a small value'
7468                });
7469              }
7470
7471              this.manifest.segments = uris;
7472            },
7473            key: function key() {
7474              if (!entry.attributes) {
7475                this.trigger('warn', {
7476                  message: 'ignoring key declaration without attribute list'
7477                });
7478                return;
7479              }
7480              // clear the active encryption key
7481              if (entry.attributes.METHOD === 'NONE') {
7482                _key = null;
7483                return;
7484              }
7485              if (!entry.attributes.URI) {
7486                this.trigger('warn', {
7487                  message: 'ignoring key declaration without URI'
7488                });
7489                return;
7490              }
7491              if (!entry.attributes.METHOD) {
7492                this.trigger('warn', {
7493                  message: 'defaulting key method to AES-128'
7494                });
7495              }
7496
7497              // setup an encryption key for upcoming segments
7498              _key = {
7499                method: entry.attributes.METHOD || 'AES-128',
7500                uri: entry.attributes.URI
7501              };
7502
7503              if (typeof entry.attributes.IV !== 'undefined') {
7504                _key.iv = entry.attributes.IV;
7505              }
7506            },
7507            'media-sequence': function mediaSequence() {
7508              if (!isFinite(entry.number)) {
7509                this.trigger('warn', {
7510                  message: 'ignoring invalid media sequence: ' + entry.number
7511                });
7512                return;
7513              }
7514              this.manifest.mediaSequence = entry.number;
7515            },
7516            'discontinuity-sequence': function discontinuitySequence() {
7517              if (!isFinite(entry.number)) {
7518                this.trigger('warn', {
7519                  message: 'ignoring invalid discontinuity sequence: ' + entry.number
7520                });
7521                return;
7522              }
7523              this.manifest.discontinuitySequence = entry.number;
7524              currentTimeline = entry.number;
7525            },
7526            'playlist-type': function playlistType() {
7527              if (!/VOD|EVENT/.test(entry.playlistType)) {
7528                this.trigger('warn', {
7529                  message: 'ignoring unknown playlist type: ' + entry.playlist
7530                });
7531                return;
7532              }
7533              this.manifest.playlistType = entry.playlistType;
7534            },
7535            map: function map() {
7536              currentMap = {};
7537              if (entry.uri) {
7538                currentMap.uri = entry.uri;
7539              }
7540              if (entry.byterange) {
7541                currentMap.byterange = entry.byterange;
7542              }
7543            },
7544            'stream-inf': function streamInf() {
7545              this.manifest.playlists = uris;
7546              this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;
7547
7548              if (!entry.attributes) {
7549                this.trigger('warn', {
7550                  message: 'ignoring empty stream-inf attributes'
7551                });
7552                return;
7553              }
7554
7555              if (!currentUri.attributes) {
7556                currentUri.attributes = {};
7557              }
7558              currentUri.attributes = (0, _lodashCompatObjectMerge2['default'])(currentUri.attributes, entry.attributes);
7559            },
7560            media: function media() {
7561              this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;
7562
7563              if (!(entry.attributes && entry.attributes.TYPE && entry.attributes['GROUP-ID'] && entry.attributes.NAME)) {
7564                this.trigger('warn', {
7565                  message: 'ignoring incomplete or missing media group'
7566                });
7567                return;
7568              }
7569
7570              // find the media group, creating defaults as necessary
7571              var mediaGroupType = this.manifest.mediaGroups[entry.attributes.TYPE];
7572
7573              mediaGroupType[entry.attributes['GROUP-ID']] = mediaGroupType[entry.attributes['GROUP-ID']] || {};
7574              mediaGroup = mediaGroupType[entry.attributes['GROUP-ID']];
7575
7576              // collect the rendition metadata
7577              rendition = {
7578                'default': /yes/i.test(entry.attributes.DEFAULT)
7579              };
7580              if (rendition['default']) {
7581                rendition.autoselect = true;
7582              } else {
7583                rendition.autoselect = /yes/i.test(entry.attributes.AUTOSELECT);
7584              }
7585              if (entry.attributes.LANGUAGE) {
7586                rendition.language = entry.attributes.LANGUAGE;
7587              }
7588              if (entry.attributes.URI) {
7589                rendition.uri = entry.attributes.URI;
7590              }
7591              if (entry.attributes['INSTREAM-ID']) {
7592                rendition.instreamId = entry.attributes['INSTREAM-ID'];
7593              }
7594
7595              // insert the new rendition
7596              mediaGroup[entry.attributes.NAME] = rendition;
7597            },
7598            discontinuity: function discontinuity() {
7599              currentTimeline += 1;
7600              currentUri.discontinuity = true;
7601              this.manifest.discontinuityStarts.push(uris.length);
7602            },
7603            'program-date-time': function programDateTime() {
7604              this.manifest.dateTimeString = entry.dateTimeString;
7605              this.manifest.dateTimeObject = entry.dateTimeObject;
7606            },
7607            targetduration: function targetduration() {
7608              if (!isFinite(entry.duration) || entry.duration < 0) {
7609                this.trigger('warn', {
7610                  message: 'ignoring invalid target duration: ' + entry.duration
7611                });
7612                return;
7613              }
7614              this.manifest.targetDuration = entry.duration;
7615            },
7616            totalduration: function totalduration() {
7617              if (!isFinite(entry.duration) || entry.duration < 0) {
7618                this.trigger('warn', {
7619                  message: 'ignoring invalid total duration: ' + entry.duration
7620                });
7621                return;
7622              }
7623              this.manifest.totalDuration = entry.duration;
7624            },
7625            'cue-out': function cueOut() {
7626              currentUri.cueOut = entry.data;
7627            },
7628            'cue-out-cont': function cueOutCont() {
7629              currentUri.cueOutCont = entry.data;
7630            },
7631            'cue-in': function cueIn() {
7632              currentUri.cueIn = entry.data;
7633            }
7634          })[entry.tagType] || noop).call(self);
7635        },
7636        uri: function uri() {
7637          currentUri.uri = entry.uri;
7638          uris.push(currentUri);
7639
7640          // if no explicit duration was declared, use the target duration
7641          if (this.manifest.targetDuration && !('duration' in currentUri)) {
7642            this.trigger('warn', {
7643              message: 'defaulting segment duration to the target duration'
7644            });
7645            currentUri.duration = this.manifest.targetDuration;
7646          }
7647          // annotate with encryption information, if necessary
7648          if (_key) {
7649            currentUri.key = _key;
7650          }
7651          currentUri.timeline = currentTimeline;
7652          // annotate with initialization segment information, if necessary
7653          if (currentMap) {
7654            currentUri.map = currentMap;
7655          }
7656
7657          // prepare for the next URI
7658          currentUri = {};
7659        },
7660        comment: function comment() {
7661          // comments are not important for playback
7662        }
7663      })[entry.type].call(self);
7664    });
7665  }
7666
7667  /**
7668   * Parse the input string and update the manifest object.
7669   *
7670   * @param {String} chunk a potentially incomplete portion of the manifest
7671   */
7672
7673  _createClass(Parser, [{
7674    key: 'push',
7675    value: function push(chunk) {
7676      this.lineStream.push(chunk);
7677    }
7678
7679    /**
7680     * Flush any remaining input. This can be handy if the last line of an M3U8
7681     * manifest did not contain a trailing newline but the file has been
7682     * completely received.
7683     */
7684  }, {
7685    key: 'end',
7686    value: function end() {
7687      // flush any buffered input
7688      this.lineStream.push('\n');
7689    }
7690  }]);
7691
7692  return Parser;
7693})(_stream2['default']);
7694
7695exports['default'] = Parser;
7696module.exports = exports['default'];
7697},{"./line-stream":63,"./parse-stream":64,"./stream":66,"lodash-compat/object/merge":59}],66:[function(require,module,exports){
7698arguments[4][13][0].apply(exports,arguments)
7699},{"dup":13}],67:[function(require,module,exports){
7700/**
7701 * mux.js
7702 *
7703 * Copyright (c) 2016 Brightcove
7704 * All rights reserved.
7705 *
7706 * A stream-based aac to mp4 converter. This utility can be used to
7707 * deliver mp4s to a SourceBuffer on platforms that support native
7708 * Media Source Extensions.
7709 */
7710'use strict';
7711var Stream = require('../utils/stream.js');
7712
7713// Constants
7714var AacStream;
7715
7716/**
7717 * Splits an incoming stream of binary data into ADTS and ID3 Frames.
7718 */
7719
7720AacStream = function() {
7721  var
7722    everything = new Uint8Array(),
7723    timeStamp = 0;
7724
7725  AacStream.prototype.init.call(this);
7726
7727  this.setTimestamp = function(timestamp) {
7728    timeStamp = timestamp;
7729  };
7730
7731  this.parseId3TagSize = function(header, byteIndex) {
7732    var
7733      returnSize = (header[byteIndex + 6] << 21) |
7734                   (header[byteIndex + 7] << 14) |
7735                   (header[byteIndex + 8] << 7) |
7736                   (header[byteIndex + 9]),
7737      flags = header[byteIndex + 5],
7738      footerPresent = (flags & 16) >> 4;
7739
7740    if (footerPresent) {
7741      return returnSize + 20;
7742    }
7743    return returnSize + 10;
7744  };
7745
7746  this.parseAdtsSize = function(header, byteIndex) {
7747    var
7748      lowThree = (header[byteIndex + 5] & 0xE0) >> 5,
7749      middle = header[byteIndex + 4] << 3,
7750      highTwo = header[byteIndex + 3] & 0x3 << 11;
7751
7752    return (highTwo | middle) | lowThree;
7753  };
7754
7755  this.push = function(bytes) {
7756    var
7757      frameSize = 0,
7758      byteIndex = 0,
7759      bytesLeft,
7760      chunk,
7761      packet,
7762      tempLength;
7763
7764    // If there are bytes remaining from the last segment, prepend them to the
7765    // bytes that were pushed in
7766    if (everything.length) {
7767      tempLength = everything.length;
7768      everything = new Uint8Array(bytes.byteLength + tempLength);
7769      everything.set(everything.subarray(0, tempLength));
7770      everything.set(bytes, tempLength);
7771    } else {
7772      everything = bytes;
7773    }
7774
7775    while (everything.length - byteIndex >= 3) {
7776      if ((everything[byteIndex] === 'I'.charCodeAt(0)) &&
7777          (everything[byteIndex + 1] === 'D'.charCodeAt(0)) &&
7778          (everything[byteIndex + 2] === '3'.charCodeAt(0))) {
7779
7780        // Exit early because we don't have enough to parse
7781        // the ID3 tag header
7782        if (everything.length - byteIndex < 10) {
7783          break;
7784        }
7785
7786        // check framesize
7787        frameSize = this.parseId3TagSize(everything, byteIndex);
7788
7789        // Exit early if we don't have enough in the buffer
7790        // to emit a full packet
7791        if (frameSize > everything.length) {
7792          break;
7793        }
7794        chunk = {
7795          type: 'timed-metadata',
7796          data: everything.subarray(byteIndex, byteIndex + frameSize)
7797        };
7798        this.trigger('data', chunk);
7799        byteIndex += frameSize;
7800        continue;
7801      } else if ((everything[byteIndex] & 0xff === 0xff) &&
7802                 ((everything[byteIndex + 1] & 0xf0) === 0xf0)) {
7803
7804        // Exit early because we don't have enough to parse
7805        // the ADTS frame header
7806        if (everything.length - byteIndex < 7) {
7807          break;
7808        }
7809
7810        frameSize = this.parseAdtsSize(everything, byteIndex);
7811
7812        // Exit early if we don't have enough in the buffer
7813        // to emit a full packet
7814        if (frameSize > everything.length) {
7815          break;
7816        }
7817
7818        packet = {
7819          type: 'audio',
7820          data: everything.subarray(byteIndex, byteIndex + frameSize),
7821          pts: timeStamp,
7822          dts: timeStamp
7823        };
7824        this.trigger('data', packet);
7825        byteIndex += frameSize;
7826        continue;
7827      }
7828      byteIndex++;
7829    }
7830    bytesLeft = everything.length - byteIndex;
7831
7832    if (bytesLeft > 0) {
7833      everything = everything.subarray(byteIndex);
7834    } else {
7835      everything = new Uint8Array();
7836    }
7837  };
7838};
7839
7840AacStream.prototype = new Stream();
7841
7842module.exports = AacStream;
7843
7844},{"../utils/stream.js":83}],68:[function(require,module,exports){
7845'use strict';
7846
7847var Stream = require('../utils/stream.js');
7848
7849var AdtsStream;
7850
7851var
7852  ADTS_SAMPLING_FREQUENCIES = [
7853    96000,
7854    88200,
7855    64000,
7856    48000,
7857    44100,
7858    32000,
7859    24000,
7860    22050,
7861    16000,
7862    12000,
7863    11025,
7864    8000,
7865    7350
7866  ];
7867
7868/*
7869 * Accepts a ElementaryStream and emits data events with parsed
7870 * AAC Audio Frames of the individual packets. Input audio in ADTS
7871 * format is unpacked and re-emitted as AAC frames.
7872 *
7873 * @see http://wiki.multimedia.cx/index.php?title=ADTS
7874 * @see http://wiki.multimedia.cx/?title=Understanding_AAC
7875 */
7876AdtsStream = function() {
7877  var buffer;
7878
7879  AdtsStream.prototype.init.call(this);
7880
7881  this.push = function(packet) {
7882    var
7883      i = 0,
7884      frameNum = 0,
7885      frameLength,
7886      protectionSkipBytes,
7887      frameEnd,
7888      oldBuffer,
7889      sampleCount,
7890      adtsFrameDuration;
7891
7892    if (packet.type !== 'audio') {
7893      // ignore non-audio data
7894      return;
7895    }
7896
7897    // Prepend any data in the buffer to the input data so that we can parse
7898    // aac frames the cross a PES packet boundary
7899    if (buffer) {
7900      oldBuffer = buffer;
7901      buffer = new Uint8Array(oldBuffer.byteLength + packet.data.byteLength);
7902      buffer.set(oldBuffer);
7903      buffer.set(packet.data, oldBuffer.byteLength);
7904    } else {
7905      buffer = packet.data;
7906    }
7907
7908    // unpack any ADTS frames which have been fully received
7909    // for details on the ADTS header, see http://wiki.multimedia.cx/index.php?title=ADTS
7910    while (i + 5 < buffer.length) {
7911
7912      // Loook for the start of an ADTS header..
7913      if (buffer[i] !== 0xFF || (buffer[i + 1] & 0xF6) !== 0xF0) {
7914        // If a valid header was not found,  jump one forward and attempt to
7915        // find a valid ADTS header starting at the next byte
7916        i++;
7917        continue;
7918      }
7919
7920      // The protection skip bit tells us if we have 2 bytes of CRC data at the
7921      // end of the ADTS header
7922      protectionSkipBytes = (~buffer[i + 1] & 0x01) * 2;
7923
7924      // Frame length is a 13 bit integer starting 16 bits from the
7925      // end of the sync sequence
7926      frameLength = ((buffer[i + 3] & 0x03) << 11) |
7927        (buffer[i + 4] << 3) |
7928        ((buffer[i + 5] & 0xe0) >> 5);
7929
7930      sampleCount = ((buffer[i + 6] & 0x03) + 1) * 1024;
7931      adtsFrameDuration = (sampleCount * 90000) /
7932        ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2];
7933
7934      frameEnd = i + frameLength;
7935
7936      // If we don't have enough data to actually finish this ADTS frame, return
7937      // and wait for more data
7938      if (buffer.byteLength < frameEnd) {
7939        return;
7940      }
7941
7942      // Otherwise, deliver the complete AAC frame
7943      this.trigger('data', {
7944        pts: packet.pts + (frameNum * adtsFrameDuration),
7945        dts: packet.dts + (frameNum * adtsFrameDuration),
7946        sampleCount: sampleCount,
7947        audioobjecttype: ((buffer[i + 2] >>> 6) & 0x03) + 1,
7948        channelcount: ((buffer[i + 2] & 1) << 2) |
7949          ((buffer[i + 3] & 0xc0) >>> 6),
7950        samplerate: ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2],
7951        samplingfrequencyindex: (buffer[i + 2] & 0x3c) >>> 2,
7952        // assume ISO/IEC 14496-12 AudioSampleEntry default of 16
7953        samplesize: 16,
7954        data: buffer.subarray(i + 7 + protectionSkipBytes, frameEnd)
7955      });
7956
7957      // If the buffer is empty, clear it and return
7958      if (buffer.byteLength === frameEnd) {
7959        buffer = undefined;
7960        return;
7961      }
7962
7963      frameNum++;
7964
7965      // Remove the finished frame from the buffer and start the process again
7966      buffer = buffer.subarray(frameEnd);
7967    }
7968  };
7969  this.flush = function() {
7970    this.trigger('done');
7971  };
7972};
7973
7974AdtsStream.prototype = new Stream();
7975
7976module.exports = AdtsStream;
7977
7978},{"../utils/stream.js":83}],69:[function(require,module,exports){
7979'use strict';
7980
7981var Stream = require('../utils/stream.js');
7982var ExpGolomb = require('../utils/exp-golomb.js');
7983
7984var H264Stream, NalByteStream;
7985var PROFILES_WITH_OPTIONAL_SPS_DATA;
7986
7987/**
7988 * Accepts a NAL unit byte stream and unpacks the embedded NAL units.
7989 */
7990NalByteStream = function() {
7991  var
7992    syncPoint = 0,
7993    i,
7994    buffer;
7995  NalByteStream.prototype.init.call(this);
7996
7997  this.push = function(data) {
7998    var swapBuffer;
7999
8000    if (!buffer) {
8001      buffer = data.data;
8002    } else {
8003      swapBuffer = new Uint8Array(buffer.byteLength + data.data.byteLength);
8004      swapBuffer.set(buffer);
8005      swapBuffer.set(data.data, buffer.byteLength);
8006      buffer = swapBuffer;
8007    }
8008
8009    // Rec. ITU-T H.264, Annex B
8010    // scan for NAL unit boundaries
8011
8012    // a match looks like this:
8013    // 0 0 1 .. NAL .. 0 0 1
8014    // ^ sync point        ^ i
8015    // or this:
8016    // 0 0 1 .. NAL .. 0 0 0
8017    // ^ sync point        ^ i
8018
8019    // advance the sync point to a NAL start, if necessary
8020    for (; syncPoint < buffer.byteLength - 3; syncPoint++) {
8021      if (buffer[syncPoint + 2] === 1) {
8022        // the sync point is properly aligned
8023        i = syncPoint + 5;
8024        break;
8025      }
8026    }
8027
8028    while (i < buffer.byteLength) {
8029      // look at the current byte to determine if we've hit the end of
8030      // a NAL unit boundary
8031      switch (buffer[i]) {
8032      case 0:
8033        // skip past non-sync sequences
8034        if (buffer[i - 1] !== 0) {
8035          i += 2;
8036          break;
8037        } else if (buffer[i - 2] !== 0) {
8038          i++;
8039          break;
8040        }
8041
8042        // deliver the NAL unit if it isn't empty
8043        if (syncPoint + 3 !== i - 2) {
8044          this.trigger('data', buffer.subarray(syncPoint + 3, i - 2));
8045        }
8046
8047        // drop trailing zeroes
8048        do {
8049          i++;
8050        } while (buffer[i] !== 1 && i < buffer.length);
8051        syncPoint = i - 2;
8052        i += 3;
8053        break;
8054      case 1:
8055        // skip past non-sync sequences
8056        if (buffer[i - 1] !== 0 ||
8057            buffer[i - 2] !== 0) {
8058          i += 3;
8059          break;
8060        }
8061
8062        // deliver the NAL unit
8063        this.trigger('data', buffer.subarray(syncPoint + 3, i - 2));
8064        syncPoint = i - 2;
8065        i += 3;
8066        break;
8067      default:
8068        // the current byte isn't a one or zero, so it cannot be part
8069        // of a sync sequence
8070        i += 3;
8071        break;
8072      }
8073    }
8074    // filter out the NAL units that were delivered
8075    buffer = buffer.subarray(syncPoint);
8076    i -= syncPoint;
8077    syncPoint = 0;
8078  };
8079
8080  this.flush = function() {
8081    // deliver the last buffered NAL unit
8082    if (buffer && buffer.byteLength > 3) {
8083      this.trigger('data', buffer.subarray(syncPoint + 3));
8084    }
8085    // reset the stream state
8086    buffer = null;
8087    syncPoint = 0;
8088    this.trigger('done');
8089  };
8090};
8091NalByteStream.prototype = new Stream();
8092
8093// values of profile_idc that indicate additional fields are included in the SPS
8094// see Recommendation ITU-T H.264 (4/2013),
8095// 7.3.2.1.1 Sequence parameter set data syntax
8096PROFILES_WITH_OPTIONAL_SPS_DATA = {
8097  100: true,
8098  110: true,
8099  122: true,
8100  244: true,
8101  44: true,
8102  83: true,
8103  86: true,
8104  118: true,
8105  128: true,
8106  138: true,
8107  139: true,
8108  134: true
8109};
8110
8111/**
8112 * Accepts input from a ElementaryStream and produces H.264 NAL unit data
8113 * events.
8114 */
8115H264Stream = function() {
8116  var
8117    nalByteStream = new NalByteStream(),
8118    self,
8119    trackId,
vendor: 16,380 bytes, lines 8120-8633
8120    currentPts,
8121    currentDts,
8122
8123    discardEmulationPreventionBytes,
8124    readSequenceParameterSet,
8125    skipScalingList;
8126
8127  H264Stream.prototype.init.call(this);
8128  self = this;
8129
8130  this.push = function(packet) {
8131    if (packet.type !== 'video') {
8132      return;
8133    }
8134    trackId = packet.trackId;
8135    currentPts = packet.pts;
8136    currentDts = packet.dts;
8137
8138    nalByteStream.push(packet);
8139  };
8140
8141  nalByteStream.on('data', function(data) {
8142    var
8143      event = {
8144        trackId: trackId,
8145        pts: currentPts,
8146        dts: currentDts,
8147        data: data
8148      };
8149
8150    switch (data[0] & 0x1f) {
8151    case 0x05:
8152      event.nalUnitType = 'slice_layer_without_partitioning_rbsp_idr';
8153      break;
8154    case 0x06:
8155      event.nalUnitType = 'sei_rbsp';
8156      event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1));
8157      break;
8158    case 0x07:
8159      event.nalUnitType = 'seq_parameter_set_rbsp';
8160      event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1));
8161      event.config = readSequenceParameterSet(event.escapedRBSP);
8162      break;
8163    case 0x08:
8164      event.nalUnitType = 'pic_parameter_set_rbsp';
8165      break;
8166    case 0x09:
8167      event.nalUnitType = 'access_unit_delimiter_rbsp';
8168      break;
8169
8170    default:
8171      break;
8172    }
8173    self.trigger('data', event);
8174  });
8175  nalByteStream.on('done', function() {
8176    self.trigger('done');
8177  });
8178
8179  this.flush = function() {
8180    nalByteStream.flush();
8181  };
8182
8183  /**
8184   * Advance the ExpGolomb decoder past a scaling list. The scaling
8185   * list is optionally transmitted as part of a sequence parameter
8186   * set and is not relevant to transmuxing.
8187   * @param count {number} the number of entries in this scaling list
8188   * @param expGolombDecoder {object} an ExpGolomb pointed to the
8189   * start of a scaling list
8190   * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
8191   */
8192  skipScalingList = function(count, expGolombDecoder) {
8193    var
8194      lastScale = 8,
8195      nextScale = 8,
8196      j,
8197      deltaScale;
8198
8199    for (j = 0; j < count; j++) {
8200      if (nextScale !== 0) {
8201        deltaScale = expGolombDecoder.readExpGolomb();
8202        nextScale = (lastScale + deltaScale + 256) % 256;
8203      }
8204
8205      lastScale = (nextScale === 0) ? lastScale : nextScale;
8206    }
8207  };
8208
8209  /**
8210   * Expunge any "Emulation Prevention" bytes from a "Raw Byte
8211   * Sequence Payload"
8212   * @param data {Uint8Array} the bytes of a RBSP from a NAL
8213   * unit
8214   * @return {Uint8Array} the RBSP without any Emulation
8215   * Prevention Bytes
8216   */
8217  discardEmulationPreventionBytes = function(data) {
8218    var
8219      length = data.byteLength,
8220      emulationPreventionBytesPositions = [],
8221      i = 1,
8222      newLength, newData;
8223
8224    // Find all `Emulation Prevention Bytes`
8225    while (i < length - 2) {
8226      if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0x03) {
8227        emulationPreventionBytesPositions.push(i + 2);
8228        i += 2;
8229      } else {
8230        i++;
8231      }
8232    }
8233
8234    // If no Emulation Prevention Bytes were found just return the original
8235    // array
8236    if (emulationPreventionBytesPositions.length === 0) {
8237      return data;
8238    }
8239
8240    // Create a new array to hold the NAL unit data
8241    newLength = length - emulationPreventionBytesPositions.length;
8242    newData = new Uint8Array(newLength);
8243    var sourceIndex = 0;
8244
8245    for (i = 0; i < newLength; sourceIndex++, i++) {
8246      if (sourceIndex === emulationPreventionBytesPositions[0]) {
8247        // Skip this byte
8248        sourceIndex++;
8249        // Remove this position index
8250        emulationPreventionBytesPositions.shift();
8251      }
8252      newData[i] = data[sourceIndex];
8253    }
8254
8255    return newData;
8256  };
8257
8258  /**
8259   * Read a sequence parameter set and return some interesting video
8260   * properties. A sequence parameter set is the H264 metadata that
8261   * describes the properties of upcoming video frames.
8262   * @param data {Uint8Array} the bytes of a sequence parameter set
8263   * @return {object} an object with configuration parsed from the
8264   * sequence parameter set, including the dimensions of the
8265   * associated video frames.
8266   */
8267  readSequenceParameterSet = function(data) {
8268    var
8269      frameCropLeftOffset = 0,
8270      frameCropRightOffset = 0,
8271      frameCropTopOffset = 0,
8272      frameCropBottomOffset = 0,
8273      sarScale = 1,
8274      expGolombDecoder, profileIdc, levelIdc, profileCompatibility,
8275      chromaFormatIdc, picOrderCntType,
8276      numRefFramesInPicOrderCntCycle, picWidthInMbsMinus1,
8277      picHeightInMapUnitsMinus1,
8278      frameMbsOnlyFlag,
8279      scalingListCount,
8280      sarRatio,
8281      aspectRatioIdc,
8282      i;
8283
8284    expGolombDecoder = new ExpGolomb(data);
8285    profileIdc = expGolombDecoder.readUnsignedByte(); // profile_idc
8286    profileCompatibility = expGolombDecoder.readUnsignedByte(); // constraint_set[0-5]_flag
8287    levelIdc = expGolombDecoder.readUnsignedByte(); // level_idc u(8)
8288    expGolombDecoder.skipUnsignedExpGolomb(); // seq_parameter_set_id
8289
8290    // some profiles have more optional data we don't need
8291    if (PROFILES_WITH_OPTIONAL_SPS_DATA[profileIdc]) {
8292      chromaFormatIdc = expGolombDecoder.readUnsignedExpGolomb();
8293      if (chromaFormatIdc === 3) {
8294        expGolombDecoder.skipBits(1); // separate_colour_plane_flag
8295      }
8296      expGolombDecoder.skipUnsignedExpGolomb(); // bit_depth_luma_minus8
8297      expGolombDecoder.skipUnsignedExpGolomb(); // bit_depth_chroma_minus8
8298      expGolombDecoder.skipBits(1); // qpprime_y_zero_transform_bypass_flag
8299      if (expGolombDecoder.readBoolean()) { // seq_scaling_matrix_present_flag
8300        scalingListCount = (chromaFormatIdc !== 3) ? 8 : 12;
8301        for (i = 0; i < scalingListCount; i++) {
8302          if (expGolombDecoder.readBoolean()) { // seq_scaling_list_present_flag[ i ]
8303            if (i < 6) {
8304              skipScalingList(16, expGolombDecoder);
8305            } else {
8306              skipScalingList(64, expGolombDecoder);
8307            }
8308          }
8309        }
8310      }
8311    }
8312
8313    expGolombDecoder.skipUnsignedExpGolomb(); // log2_max_frame_num_minus4
8314    picOrderCntType = expGolombDecoder.readUnsignedExpGolomb();
8315
8316    if (picOrderCntType === 0) {
8317      expGolombDecoder.readUnsignedExpGolomb(); // log2_max_pic_order_cnt_lsb_minus4
8318    } else if (picOrderCntType === 1) {
8319      expGolombDecoder.skipBits(1); // delta_pic_order_always_zero_flag
8320      expGolombDecoder.skipExpGolomb(); // offset_for_non_ref_pic
8321      expGolombDecoder.skipExpGolomb(); // offset_for_top_to_bottom_field
8322      numRefFramesInPicOrderCntCycle = expGolombDecoder.readUnsignedExpGolomb();
8323      for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
8324        expGolombDecoder.skipExpGolomb(); // offset_for_ref_frame[ i ]
8325      }
8326    }
8327
8328    expGolombDecoder.skipUnsignedExpGolomb(); // max_num_ref_frames
8329    expGolombDecoder.skipBits(1); // gaps_in_frame_num_value_allowed_flag
8330
8331    picWidthInMbsMinus1 = expGolombDecoder.readUnsignedExpGolomb();
8332    picHeightInMapUnitsMinus1 = expGolombDecoder.readUnsignedExpGolomb();
8333
8334    frameMbsOnlyFlag = expGolombDecoder.readBits(1);
8335    if (frameMbsOnlyFlag === 0) {
8336      expGolombDecoder.skipBits(1); // mb_adaptive_frame_field_flag
8337    }
8338
8339    expGolombDecoder.skipBits(1); // direct_8x8_inference_flag
8340    if (expGolombDecoder.readBoolean()) { // frame_cropping_flag
8341      frameCropLeftOffset = expGolombDecoder.readUnsignedExpGolomb();
8342      frameCropRightOffset = expGolombDecoder.readUnsignedExpGolomb();
8343      frameCropTopOffset = expGolombDecoder.readUnsignedExpGolomb();
8344      frameCropBottomOffset = expGolombDecoder.readUnsignedExpGolomb();
8345    }
8346    if (expGolombDecoder.readBoolean()) {
8347      // vui_parameters_present_flag
8348      if (expGolombDecoder.readBoolean()) {
8349        // aspect_ratio_info_present_flag
8350        aspectRatioIdc = expGolombDecoder.readUnsignedByte();
8351        switch (aspectRatioIdc) {
8352          case 1: sarRatio = [1, 1]; break;
8353          case 2: sarRatio = [12, 11]; break;
8354          case 3: sarRatio = [10, 11]; break;
8355          case 4: sarRatio = [16, 11]; break;
8356          case 5: sarRatio = [40, 33]; break;
8357          case 6: sarRatio = [24, 11]; break;
8358          case 7: sarRatio = [20, 11]; break;
8359          case 8: sarRatio = [32, 11]; break;
8360          case 9: sarRatio = [80, 33]; break;
8361          case 10: sarRatio = [18, 11]; break;
8362          case 11: sarRatio = [15, 11]; break;
8363          case 12: sarRatio = [64, 33]; break;
8364          case 13: sarRatio = [160, 99]; break;
8365          case 14: sarRatio = [4, 3]; break;
8366          case 15: sarRatio = [3, 2]; break;
8367          case 16: sarRatio = [2, 1]; break;
8368          case 255: {
8369            sarRatio = [expGolombDecoder.readUnsignedByte() << 8 |
8370                        expGolombDecoder.readUnsignedByte(),
8371                        expGolombDecoder.readUnsignedByte() << 8 |
8372                        expGolombDecoder.readUnsignedByte() ];
8373            break;
8374          }
8375        }
8376        if (sarRatio) {
8377          sarScale = sarRatio[0] / sarRatio[1];
8378        }
8379      }
8380    }
8381    return {
8382      profileIdc: profileIdc,
8383      levelIdc: levelIdc,
8384      profileCompatibility: profileCompatibility,
8385      width: Math.ceil((((picWidthInMbsMinus1 + 1) * 16) - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale),
8386      height: ((2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16) - (frameCropTopOffset * 2) - (frameCropBottomOffset * 2)
8387    };
8388  };
8389
8390};
8391H264Stream.prototype = new Stream();
8392
8393module.exports = {
8394  H264Stream: H264Stream,
8395  NalByteStream: NalByteStream
8396};
8397
8398},{"../utils/exp-golomb.js":82,"../utils/stream.js":83}],70:[function(require,module,exports){
8399/**
8400 * An object that stores the bytes of an FLV tag and methods for
8401 * querying and manipulating that data.
8402 * @see http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
8403 */
8404'use strict';
8405
8406var FlvTag;
8407
8408// (type:uint, extraData:Boolean = false) extends ByteArray
8409FlvTag = function(type, extraData) {
8410  var
8411    // Counter if this is a metadata tag, nal start marker if this is a video
8412    // tag. unused if this is an audio tag
8413    adHoc = 0, // :uint
8414
8415    // The default size is 16kb but this is not enough to hold iframe
8416    // data and the resizing algorithm costs a bit so we create a larger
8417    // starting buffer for video tags
8418    bufferStartSize = 16384,
8419
8420    // checks whether the FLV tag has enough capacity to accept the proposed
8421    // write and re-allocates the internal buffers if necessary
8422    prepareWrite = function(flv, count) {
8423      var
8424        bytes,
8425        minLength = flv.position + count;
8426      if (minLength < flv.bytes.byteLength) {
8427        // there's enough capacity so do nothing
8428        return;
8429      }
8430
8431      // allocate a new buffer and copy over the data that will not be modified
8432      bytes = new Uint8Array(minLength * 2);
8433      bytes.set(flv.bytes.subarray(0, flv.position), 0);
8434      flv.bytes = bytes;
8435      flv.view = new DataView(flv.bytes.buffer);
8436    },
8437
8438    // commonly used metadata properties
8439    widthBytes = FlvTag.widthBytes || new Uint8Array('width'.length),
8440    heightBytes = FlvTag.heightBytes || new Uint8Array('height'.length),
8441    videocodecidBytes = FlvTag.videocodecidBytes || new Uint8Array('videocodecid'.length),
8442    i;
8443
8444  if (!FlvTag.widthBytes) {
8445    // calculating the bytes of common metadata names ahead of time makes the
8446    // corresponding writes faster because we don't have to loop over the
8447    // characters
8448    // re-test with test/perf.html if you're planning on changing this
8449    for (i = 0; i < 'width'.length; i++) {
8450      widthBytes[i] = 'width'.charCodeAt(i);
8451    }
8452    for (i = 0; i < 'height'.length; i++) {
8453      heightBytes[i] = 'height'.charCodeAt(i);
8454    }
8455    for (i = 0; i < 'videocodecid'.length; i++) {
8456      videocodecidBytes[i] = 'videocodecid'.charCodeAt(i);
8457    }
8458
8459    FlvTag.widthBytes = widthBytes;
8460    FlvTag.heightBytes = heightBytes;
8461    FlvTag.videocodecidBytes = videocodecidBytes;
8462  }
8463
8464  this.keyFrame = false; // :Boolean
8465
8466  switch (type) {
8467  case FlvTag.VIDEO_TAG:
8468    this.length = 16;
8469    // Start the buffer at 256k
8470    bufferStartSize *= 6;
8471    break;
8472  case FlvTag.AUDIO_TAG:
8473    this.length = 13;
8474    this.keyFrame = true;
8475    break;
8476  case FlvTag.METADATA_TAG:
8477    this.length = 29;
8478    this.keyFrame = true;
8479    break;
8480  default:
8481    throw new Error('Unknown FLV tag type');
8482  }
8483
8484  this.bytes = new Uint8Array(bufferStartSize);
8485  this.view = new DataView(this.bytes.buffer);
8486  this.bytes[0] = type;
8487  this.position = this.length;
8488  this.keyFrame = extraData; // Defaults to false
8489
8490  // presentation timestamp
8491  this.pts = 0;
8492  // decoder timestamp
8493  this.dts = 0;
8494
8495  // ByteArray#writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0)
8496  this.writeBytes = function(bytes, offset, length) {
8497    var
8498      start = offset || 0,
8499      end;
8500    length = length || bytes.byteLength;
8501    end = start + length;
8502
8503    prepareWrite(this, length);
8504    this.bytes.set(bytes.subarray(start, end), this.position);
8505
8506    this.position += length;
8507    this.length = Math.max(this.length, this.position);
8508  };
8509
8510  // ByteArray#writeByte(value:int):void
8511  this.writeByte = function(byte) {
8512    prepareWrite(this, 1);
8513    this.bytes[this.position] = byte;
8514    this.position++;
8515    this.length = Math.max(this.length, this.position);
8516  };
8517
8518  // ByteArray#writeShort(value:int):void
8519  this.writeShort = function(short) {
8520    prepareWrite(this, 2);
8521    this.view.setUint16(this.position, short);
8522    this.position += 2;
8523    this.length = Math.max(this.length, this.position);
8524  };
8525
8526  // Negative index into array
8527  // (pos:uint):int
8528  this.negIndex = function(pos) {
8529    return this.bytes[this.length - pos];
8530  };
8531
8532  // The functions below ONLY work when this[0] == VIDEO_TAG.
8533  // We are not going to check for that because we dont want the overhead
8534  // (nal:ByteArray = null):int
8535  this.nalUnitSize = function() {
8536    if (adHoc === 0) {
8537      return 0;
8538    }
8539
8540    return this.length - (adHoc + 4);
8541  };
8542
8543  this.startNalUnit = function() {
8544    // remember position and add 4 bytes
8545    if (adHoc > 0) {
8546      throw new Error('Attempted to create new NAL wihout closing the old one');
8547    }
8548
8549    // reserve 4 bytes for nal unit size
8550    adHoc = this.length;
8551    this.length += 4;
8552    this.position = this.length;
8553  };
8554
8555  // (nal:ByteArray = null):void
8556  this.endNalUnit = function(nalContainer) {
8557    var
8558      nalStart, // :uint
8559      nalLength; // :uint
8560
8561    // Rewind to the marker and write the size
8562    if (this.length === adHoc + 4) {
8563      // we started a nal unit, but didnt write one, so roll back the 4 byte size value
8564      this.length -= 4;
8565    } else if (adHoc > 0) {
8566      nalStart = adHoc + 4;
8567      nalLength = this.length - nalStart;
8568
8569      this.position = adHoc;
8570      this.view.setUint32(this.position, nalLength);
8571      this.position = this.length;
8572
8573      if (nalContainer) {
8574        // Add the tag to the NAL unit
8575        nalContainer.push(this.bytes.subarray(nalStart, nalStart + nalLength));
8576      }
8577    }
8578
8579    adHoc = 0;
8580  };
8581
8582  /**
8583   * Write out a 64-bit floating point valued metadata property. This method is
8584   * called frequently during a typical parse and needs to be fast.
8585   */
8586  // (key:String, val:Number):void
8587  this.writeMetaDataDouble = function(key, val) {
8588    var i;
8589    prepareWrite(this, 2 + key.length + 9);
8590
8591    // write size of property name
8592    this.view.setUint16(this.position, key.length);
8593    this.position += 2;
8594
8595    // this next part looks terrible but it improves parser throughput by
8596    // 10kB/s in my testing
8597
8598    // write property name
8599    if (key === 'width') {
8600      this.bytes.set(widthBytes, this.position);
8601      this.position += 5;
8602    } else if (key === 'height') {
8603      this.bytes.set(heightBytes, this.position);
8604      this.position += 6;
8605    } else if (key === 'videocodecid') {
8606      this.bytes.set(videocodecidBytes, this.position);
8607      this.position += 12;
8608    } else {
8609      for (i = 0; i < key.length; i++) {
8610        this.bytes[this.position] = key.charCodeAt(i);
8611        this.position++;
8612      }
8613    }
8614
8615    // skip null byte
8616    this.position++;
8617
8618    // write property value
8619    this.view.setFloat64(this.position, val);
8620    this.position += 8;
8621
8622    // update flv tag length
8623    this.length = Math.max(this.length, this.position);
8624    ++adHoc;
8625  };
8626
8627  // (key:String, val:Boolean):void
8628  this.writeMetaDataBoolean = function(key, val) {
8629    var i;
8630    prepareWrite(this, 2);
8631    this.view.setUint16(this.position, key.length);
8632    this.position += 2;
8633    for (i = 0; i < key.length; i++) {
8634      // if key.charCodeAt(i) >= 255, handle error
8635      prepareWrite(this, 1);
8636      this.bytes[this.position] = key.charCodeAt(i);
8637      this.position++;
8638    }
8639    prepareWrite(this, 2);
8640    this.view.setUint8(this.position, 0x01);
8641    this.position++;
8642    this.view.setUint8(this.position, val ? 0x01 : 0x00);
8643    this.position++;
8644    this.length = Math.max(this.length, this.position);
8645    ++adHoc;
8646  };
8647
8648  // ():ByteArray
8649  this.finalize = function() {
8650    var
8651      dtsDelta, // :int
8652      len; // :int
8653
8654    switch (this.bytes[0]) {
8655      // Video Data
8656    case FlvTag.VIDEO_TAG:
8657       // We only support AVC, 1 = key frame (for AVC, a seekable
8658       // frame), 2 = inter frame (for AVC, a non-seekable frame)
8659      this.bytes[11] = ((this.keyFrame || extraData) ? 0x10 : 0x20) | 0x07;
8660      this.bytes[12] = extraData ?  0x00 : 0x01;
8661
8662      dtsDelta = this.pts - this.dts;
8663      this.bytes[13] = (dtsDelta & 0x00FF0000) >>> 16;
8664      this.bytes[14] = (dtsDelta & 0x0000FF00) >>>  8;
8665      this.bytes[15] = (dtsDelta & 0x000000FF) >>>  0;
8666      break;
8667
8668    case FlvTag.AUDIO_TAG:
8669      this.bytes[11] = 0xAF; // 44 kHz, 16-bit stereo
8670      this.bytes[12] = extraData ? 0x00 : 0x01;
8671      break;
8672
8673    case FlvTag.METADATA_TAG:
8674      this.position = 11;
8675      this.view.setUint8(this.position, 0x02); // String type
8676      this.position++;
8677      this.view.setUint16(this.position, 0x0A); // 10 Bytes
8678      this.position += 2;
8679      // set "onMetaData"
8680      this.bytes.set([0x6f, 0x6e, 0x4d, 0x65,
8681                      0x74, 0x61, 0x44, 0x61,
8682                      0x74, 0x61], this.position);
8683      this.position += 10;
8684      this.bytes[this.position] = 0x08; // Array type
8685      this.position++;
8686      this.view.setUint32(this.position, adHoc);
8687      this.position = this.length;
8688      this.bytes.set([0, 0, 9], this.position);
8689      this.position += 3; // End Data Tag
8690      this.length = this.position;
8691      break;
8692    }
8693
8694    len = this.length - 11;
8695
8696    // write the DataSize field
8697    this.bytes[ 1] = (len & 0x00FF0000) >>> 16;
8698    this.bytes[ 2] = (len & 0x0000FF00) >>>  8;
8699    this.bytes[ 3] = (len & 0x000000FF) >>>  0;
8700    // write the Timestamp
8701    this.bytes[ 4] = (this.dts & 0x00FF0000) >>> 16;
8702    this.bytes[ 5] = (this.dts & 0x0000FF00) >>>  8;
8703    this.bytes[ 6] = (this.dts & 0x000000FF) >>>  0;
8704    this.bytes[ 7] = (this.dts & 0xFF000000) >>> 24;
8705    // write the StreamID
8706    this.bytes[ 8] = 0;
8707    this.bytes[ 9] = 0;
8708    this.bytes[10] = 0;
8709
8710    // Sometimes we're at the end of the view and have one slot to write a
8711    // uint32, so, prepareWrite of count 4, since, view is uint8
8712    prepareWrite(this, 4);
8713    this.view.setUint32(this.length, this.length);
8714    this.length += 4;
8715    this.position += 4;
8716
8717    // trim down the byte buffer to what is actually being used
8718    this.bytes = this.bytes.subarray(0, this.length);
8719    this.frameTime = FlvTag.frameTime(this.bytes);
8720    // if bytes.bytelength isn't equal to this.length, handle error
8721    return this;
8722  };
8723};
8724
8725FlvTag.AUDIO_TAG = 0x08; // == 8, :uint
8726FlvTag.VIDEO_TAG = 0x09; // == 9, :uint
8727FlvTag.METADATA_TAG = 0x12; // == 18, :uint
8728
8729// (tag:ByteArray):Boolean {
8730FlvTag.isAudioFrame = function(tag) {
8731  return FlvTag.AUDIO_TAG === tag[0];
8732};
8733
8734// (tag:ByteArray):Boolean {
8735FlvTag.isVideoFrame = function(tag) {
8736  return FlvTag.VIDEO_TAG === tag[0];
8737};
8738
8739// (tag:ByteArray):Boolean {
8740FlvTag.isMetaData = function(tag) {
8741  return FlvTag.METADATA_TAG === tag[0];
8742};
8743
8744// (tag:ByteArray):Boolean {
8745FlvTag.isKeyFrame = function(tag) {
8746  if (FlvTag.isVideoFrame(tag)) {
8747    return tag[11] === 0x17;
8748  }
8749
8750  if (FlvTag.isAudioFrame(tag)) {
8751    return true;
8752  }
8753
8754  if (FlvTag.isMetaData(tag)) {
8755    return true;
8756  }
8757
8758  return false;
8759};
8760
8761// (tag:ByteArray):uint {
8762FlvTag.frameTime = function(tag) {
8763  var pts = tag[ 4] << 16; // :uint
8764  pts |= tag[ 5] <<  8;
8765  pts |= tag[ 6] <<  0;
8766  pts |= tag[ 7] << 24;
8767  return pts;
8768};
8769
8770module.exports = FlvTag;
8771
8772},{}],71:[function(require,module,exports){
8773module.exports = {
8774  tag: require('./flv-tag'),
8775  Transmuxer: require('./transmuxer')
8776};
8777
8778},{"./flv-tag":70,"./transmuxer":72}],72:[function(require,module,exports){
8779'use strict';
8780
8781var Stream = require('../utils/stream.js');
8782var FlvTag = require('./flv-tag.js');
8783var m2ts = require('../m2ts/m2ts.js');
8784var AdtsStream = require('../codecs/adts.js');
8785var H264Stream = require('../codecs/h264').H264Stream;
8786
8787var
8788  Transmuxer,
8789  VideoSegmentStream,
8790  AudioSegmentStream,
8791  CoalesceStream,
8792  collectTimelineInfo,
8793  metaDataTag,
8794  extraDataTag;
8795
8796/**
8797 * Store information about the start and end of the tracka and the
8798 * duration for each frame/sample we process in order to calculate
8799 * the baseMediaDecodeTime
8800 */
8801collectTimelineInfo = function(track, data) {
8802  if (typeof data.pts === 'number') {
8803    if (track.timelineStartInfo.pts === undefined) {
8804      track.timelineStartInfo.pts = data.pts;
8805    } else {
8806      track.timelineStartInfo.pts =
8807        Math.min(track.timelineStartInfo.pts, data.pts);
8808    }
8809  }
8810
8811  if (typeof data.dts === 'number') {
8812    if (track.timelineStartInfo.dts === undefined) {
8813      track.timelineStartInfo.dts = data.dts;
8814    } else {
8815      track.timelineStartInfo.dts =
8816        Math.min(track.timelineStartInfo.dts, data.dts);
8817    }
8818  }
8819};
8820
8821metaDataTag = function(track, pts) {
8822  var
8823    tag = new FlvTag(FlvTag.METADATA_TAG); // :FlvTag
8824
8825  tag.dts = pts;
8826  tag.pts = pts;
8827
8828  tag.writeMetaDataDouble('videocodecid', 7);
8829  tag.writeMetaDataDouble('width', track.width);
8830  tag.writeMetaDataDouble('height', track.height);
8831
8832  return tag;
8833};
8834
8835extraDataTag = function(track, pts) {
8836  var
8837    i,
8838    tag = new FlvTag(FlvTag.VIDEO_TAG, true);
8839
8840  tag.dts = pts;
8841  tag.pts = pts;
8842
8843  tag.writeByte(0x01);// version
8844  tag.writeByte(track.profileIdc);// profile
8845  tag.writeByte(track.profileCompatibility);// compatibility
8846  tag.writeByte(track.levelIdc);// level
8847  tag.writeByte(0xFC | 0x03); // reserved (6 bits), NULA length size - 1 (2 bits)
8848  tag.writeByte(0xE0 | 0x01); // reserved (3 bits), num of SPS (5 bits)
8849  tag.writeShort(track.sps[0].length); // data of SPS
8850  tag.writeBytes(track.sps[0]); // SPS
8851
8852  tag.writeByte(track.pps.length); // num of PPS (will there ever be more that 1 PPS?)
8853  for (i = 0; i < track.pps.length; ++i) {
8854    tag.writeShort(track.pps[i].length); // 2 bytes for length of PPS
8855    tag.writeBytes(track.pps[i]); // data of PPS
8856  }
8857
8858  return tag;
8859};
8860
8861/**
8862 * Constructs a single-track, media segment from AAC data
8863 * events. The output of this stream can be fed to flash.
8864 */
8865AudioSegmentStream = function(track) {
8866  var
8867    adtsFrames = [],
8868    oldExtraData;
8869
8870  AudioSegmentStream.prototype.init.call(this);
8871
8872  this.push = function(data) {
8873    collectTimelineInfo(track, data);
8874
8875    if (track && track.channelcount === undefined) {
8876      track.audioobjecttype = data.audioobjecttype;
8877      track.channelcount = data.channelcount;
8878      track.samplerate = data.samplerate;
8879      track.samplingfrequencyindex = data.samplingfrequencyindex;
8880      track.samplesize = data.samplesize;
8881      track.extraData = (track.audioobjecttype << 11) |
8882                        (track.samplingfrequencyindex << 7) |
8883                        (track.channelcount << 3);
8884    }
8885
8886    data.pts = Math.round(data.pts / 90);
8887    data.dts = Math.round(data.dts / 90);
8888
8889    // buffer audio data until end() is called
8890    adtsFrames.push(data);
8891  };
8892
8893  this.flush = function() {
8894    var currentFrame, adtsFrame, lastMetaPts, tags = [];
8895    // return early if no audio data has been observed
8896    if (adtsFrames.length === 0) {
8897      this.trigger('done');
8898      return;
8899    }
8900
8901    lastMetaPts = -Infinity;
8902
8903    while (adtsFrames.length) {
8904      currentFrame = adtsFrames.shift();
8905
8906      // write out metadata tags every 1 second so that the decoder
8907      // is re-initialized quickly after seeking into a different
8908      // audio configuration
8909      if (track.extraData !== oldExtraData || currentFrame.pts - lastMetaPts >= 1000) {
8910       adtsFrame = new FlvTag(FlvTag.METADATA_TAG);
8911        adtsFrame.pts = currentFrame.pts;
8912        adtsFrame.dts = currentFrame.dts;
8913
8914        // AAC is always 10
8915        adtsFrame.writeMetaDataDouble('audiocodecid', 10);
8916        adtsFrame.writeMetaDataBoolean('stereo', track.channelcount === 2);
8917        adtsFrame.writeMetaDataDouble('audiosamplerate', track.samplerate);
8918        // Is AAC always 16 bit?
8919        adtsFrame.writeMetaDataDouble('audiosamplesize', 16);
8920
8921        tags.push(adtsFrame);
8922
8923        oldExtraData = track.extraData;
8924
8925        adtsFrame = new FlvTag(FlvTag.AUDIO_TAG, true);
8926        // For audio, DTS is always the same as PTS. We want to set the DTS
8927        // however so we can compare with video DTS to determine approximate
8928        // packet order
8929        adtsFrame.pts = currentFrame.pts;
8930        adtsFrame.dts = currentFrame.dts;
8931
8932        adtsFrame.view.setUint16(adtsFrame.position, track.extraData);
8933        adtsFrame.position += 2;
8934        adtsFrame.length = Math.max(adtsFrame.length, adtsFrame.position);
8935
8936        tags.push(adtsFrame);
8937
8938        lastMetaPts = currentFrame.pts;
8939      }
8940      adtsFrame = new FlvTag(FlvTag.AUDIO_TAG);
8941      adtsFrame.pts = currentFrame.pts;
8942      adtsFrame.dts = currentFrame.dts;
8943
8944      adtsFrame.writeBytes(currentFrame.data);
8945
8946      tags.push(adtsFrame);
8947    }
8948
8949    oldExtraData = null;
8950    this.trigger('data', {track: track, tags: tags});
8951
8952    this.trigger('done');
8953  };
8954};
8955AudioSegmentStream.prototype = new Stream();
8956
8957/**
8958 * Store FlvTags for the h264 stream
8959 * @param track {object} track metadata configuration
8960 */
8961VideoSegmentStream = function(track) {
8962  var
8963    nalUnits = [],
8964    config,
8965    h264Frame;
8966  VideoSegmentStream.prototype.init.call(this);
8967
8968  this.finishFrame = function(tags, frame) {
8969    if (!frame) {
8970      return;
8971    }
8972    // Check if keyframe and the length of tags.
8973    // This makes sure we write metadata on the first frame of a segment.
8974    if (config && track && track.newMetadata &&
8975        (frame.keyFrame || tags.length === 0)) {
8976      // Push extra data on every IDR frame in case we did a stream change + seek
8977      tags.push(metaDataTag(config, frame.dts));
8978      tags.push(extraDataTag(track, frame.dts));
8979      track.newMetadata = false;
vendor: 9,458 bytes, lines 8980-9304
8980    }
8981
8982    frame.endNalUnit();
8983    tags.push(frame);
8984    h264Frame = null;
8985  };
8986
8987  this.push = function(data) {
8988    collectTimelineInfo(track, data);
8989
8990    data.pts = Math.round(data.pts / 90);
8991    data.dts = Math.round(data.dts / 90);
8992
8993    // buffer video until flush() is called
8994    nalUnits.push(data);
8995  };
8996
8997  this.flush = function() {
8998    var
8999      currentNal,
9000      tags = [];
9001
9002    // Throw away nalUnits at the start of the byte stream until we find
9003    // the first AUD
9004    while (nalUnits.length) {
9005      if (nalUnits[0].nalUnitType === 'access_unit_delimiter_rbsp') {
9006        break;
9007      }
9008      nalUnits.shift();
9009    }
9010
9011    // return early if no video data has been observed
9012    if (nalUnits.length === 0) {
9013      this.trigger('done');
9014      return;
9015    }
9016
9017    while (nalUnits.length) {
9018      currentNal = nalUnits.shift();
9019
9020      // record the track config
9021      if (currentNal.nalUnitType === 'seq_parameter_set_rbsp') {
9022        track.newMetadata = true;
9023        config = currentNal.config;
9024        track.width = config.width;
9025        track.height = config.height;
9026        track.sps = [currentNal.data];
9027        track.profileIdc = config.profileIdc;
9028        track.levelIdc = config.levelIdc;
9029        track.profileCompatibility = config.profileCompatibility;
9030        h264Frame.endNalUnit();
9031      } else if (currentNal.nalUnitType === 'pic_parameter_set_rbsp') {
9032        track.newMetadata = true;
9033        track.pps = [currentNal.data];
9034        h264Frame.endNalUnit();
9035      } else if (currentNal.nalUnitType === 'access_unit_delimiter_rbsp') {
9036        if (h264Frame) {
9037          this.finishFrame(tags, h264Frame);
9038        }
9039        h264Frame = new FlvTag(FlvTag.VIDEO_TAG);
9040        h264Frame.pts = currentNal.pts;
9041        h264Frame.dts = currentNal.dts;
9042      } else {
9043        if (currentNal.nalUnitType === 'slice_layer_without_partitioning_rbsp_idr') {
9044          // the current sample is a key frame
9045          h264Frame.keyFrame = true;
9046        }
9047        h264Frame.endNalUnit();
9048      }
9049      h264Frame.startNalUnit();
9050      h264Frame.writeBytes(currentNal.data);
9051    }
9052    if (h264Frame) {
9053      this.finishFrame(tags, h264Frame);
9054    }
9055
9056    this.trigger('data', {track: track, tags: tags});
9057
9058    // Continue with the flush process now
9059    this.trigger('done');
9060  };
9061};
9062
9063VideoSegmentStream.prototype = new Stream();
9064
9065/**
9066 * The final stage of the transmuxer that emits the flv tags
9067 * for audio, video, and metadata. Also tranlates in time and
9068 * outputs caption data and id3 cues.
9069 */
9070CoalesceStream = function(options) {
9071  // Number of Tracks per output segment
9072  // If greater than 1, we combine multiple
9073  // tracks into a single segment
9074  this.numberOfTracks = 0;
9075  this.metadataStream = options.metadataStream;
9076
9077  this.videoTags = [];
9078  this.audioTags = [];
9079  this.videoTrack = null;
9080  this.audioTrack = null;
9081  this.pendingCaptions = [];
9082  this.pendingMetadata = [];
9083  this.pendingTracks = 0;
9084
9085  CoalesceStream.prototype.init.call(this);
9086
9087  // Take output from multiple
9088  this.push = function(output) {
9089    // buffer incoming captions until the associated video segment
9090    // finishes
9091    if (output.text) {
9092      return this.pendingCaptions.push(output);
9093    }
9094    // buffer incoming id3 tags until the final flush
9095    if (output.frames) {
9096      return this.pendingMetadata.push(output);
9097    }
9098
9099    if (output.track.type === 'video') {
9100      this.videoTrack = output.track;
9101      this.videoTags = output.tags;
9102      this.pendingTracks++;
9103    }
9104    if (output.track.type === 'audio') {
9105      this.audioTrack = output.track;
9106      this.audioTags = output.tags;
9107      this.pendingTracks++;
9108    }
9109  };
9110};
9111
9112CoalesceStream.prototype = new Stream();
9113CoalesceStream.prototype.flush = function() {
9114  var
9115    id3,
9116    caption,
9117    i,
9118    timelineStartPts,
9119    event = {
9120      tags: {},
9121      captions: [],
9122      metadata: []
9123    };
9124
9125  if (this.pendingTracks < this.numberOfTracks) {
9126    return;
9127  }
9128
9129  if (this.videoTrack) {
9130    timelineStartPts = this.videoTrack.timelineStartInfo.pts;
9131  } else if (this.audioTrack) {
9132    timelineStartPts = this.audioTrack.timelineStartInfo.pts;
9133  }
9134
9135  event.tags.videoTags = this.videoTags;
9136  event.tags.audioTags = this.audioTags;
9137
9138  // Translate caption PTS times into second offsets into the
9139  // video timeline for the segment
9140  for (i = 0; i < this.pendingCaptions.length; i++) {
9141    caption = this.pendingCaptions[i];
9142    caption.startTime = caption.startPts - timelineStartPts;
9143    caption.startTime /= 90e3;
9144    caption.endTime = caption.endPts - timelineStartPts;
9145    caption.endTime /= 90e3;
9146    event.captions.push(caption);
9147  }
9148
9149  // Translate ID3 frame PTS times into second offsets into the
9150  // video timeline for the segment
9151  for (i = 0; i < this.pendingMetadata.length; i++) {
9152    id3 = this.pendingMetadata[i];
9153    id3.cueTime = id3.pts - timelineStartPts;
9154    id3.cueTime /= 90e3;
9155    event.metadata.push(id3);
9156  }
9157  // We add this to every single emitted segment even though we only need
9158  // it for the first
9159  event.metadata.dispatchType = this.metadataStream.dispatchType;
9160
9161  // Reset stream state
9162  this.videoTrack = null;
9163  this.audioTrack = null;
9164  this.videoTags = [];
9165  this.audioTags = [];
9166  this.pendingCaptions.length = 0;
9167  this.pendingMetadata.length = 0;
9168  this.pendingTracks = 0;
9169
9170  // Emit the final segment
9171  this.trigger('data', event);
9172
9173  this.trigger('done');
9174};
9175
9176/**
9177 * An object that incrementally transmuxes MPEG2 Trasport Stream
9178 * chunks into an FLV.
9179 */
9180Transmuxer = function(options) {
9181  var
9182    self = this,
9183
9184    packetStream, parseStream, elementaryStream,
9185    videoTimestampRolloverStream, audioTimestampRolloverStream,
9186    timedMetadataTimestampRolloverStream,
9187    adtsStream, h264Stream,
9188    videoSegmentStream, audioSegmentStream, captionStream,
9189    coalesceStream;
9190
9191  Transmuxer.prototype.init.call(this);
9192
9193  options = options || {};
9194
9195  // expose the metadata stream
9196  this.metadataStream = new m2ts.MetadataStream();
9197
9198  options.metadataStream = this.metadataStream;
9199
9200  // set up the parsing pipeline
9201  packetStream = new m2ts.TransportPacketStream();
9202  parseStream = new m2ts.TransportParseStream();
9203  elementaryStream = new m2ts.ElementaryStream();
9204  videoTimestampRolloverStream = new m2ts.TimestampRolloverStream('video');
9205  audioTimestampRolloverStream = new m2ts.TimestampRolloverStream('audio');
9206  timedMetadataTimestampRolloverStream = new m2ts.TimestampRolloverStream('timed-metadata');
9207
9208  adtsStream = new AdtsStream();
9209  h264Stream = new H264Stream();
9210  coalesceStream = new CoalesceStream(options);
9211
9212  // disassemble MPEG2-TS packets into elementary streams
9213  packetStream
9214    .pipe(parseStream)
9215    .pipe(elementaryStream);
9216
9217  // !!THIS ORDER IS IMPORTANT!!
9218  // demux the streams
9219  elementaryStream
9220    .pipe(videoTimestampRolloverStream)
9221    .pipe(h264Stream);
9222  elementaryStream
9223    .pipe(audioTimestampRolloverStream)
9224    .pipe(adtsStream);
9225
9226  elementaryStream
9227    .pipe(timedMetadataTimestampRolloverStream)
9228    .pipe(this.metadataStream)
9229    .pipe(coalesceStream);
9230  // if CEA-708 parsing is available, hook up a caption stream
9231  captionStream = new m2ts.CaptionStream();
9232  h264Stream.pipe(captionStream)
9233    .pipe(coalesceStream);
9234
9235  // hook up the segment streams once track metadata is delivered
9236  elementaryStream.on('data', function(data) {
9237    var i, videoTrack, audioTrack;
9238
9239    if (data.type === 'metadata') {
9240      i = data.tracks.length;
9241
9242      // scan the tracks listed in the metadata
9243      while (i--) {
9244        if (data.tracks[i].type === 'video') {
9245          videoTrack = data.tracks[i];
9246        } else if (data.tracks[i].type === 'audio') {
9247          audioTrack = data.tracks[i];
9248        }
9249      }
9250
9251      // hook up the video segment stream to the first track with h264 data
9252      if (videoTrack && !videoSegmentStream) {
9253        coalesceStream.numberOfTracks++;
9254        videoSegmentStream = new VideoSegmentStream(videoTrack);
9255
9256        // Set up the final part of the video pipeline
9257        h264Stream
9258          .pipe(videoSegmentStream)
9259          .pipe(coalesceStream);
9260      }
9261
9262      if (audioTrack && !audioSegmentStream) {
9263        // hook up the audio segment stream to the first track with aac data
9264        coalesceStream.numberOfTracks++;
9265        audioSegmentStream = new AudioSegmentStream(audioTrack);
9266
9267        // Set up the final part of the audio pipeline
9268        adtsStream
9269          .pipe(audioSegmentStream)
9270          .pipe(coalesceStream);
9271      }
9272    }
9273  });
9274
9275  // feed incoming data to the front of the parsing pipeline
9276  this.push = function(data) {
9277    packetStream.push(data);
9278  };
9279
9280  // flush any buffered data
9281  this.flush = function() {
9282    // Start at the top of the pipeline and flush all pending work
9283    packetStream.flush();
9284  };
9285
9286  // Re-emit any data coming from the coalesce stream to the outside world
9287  coalesceStream.on('data', function(event) {
9288    self.trigger('data', event);
9289  });
9290
9291  // Let the consumer know we have finished flushing the entire pipeline
9292  coalesceStream.on('done', function() {
9293    self.trigger('done');
9294  });
9295
9296  // For information on the FLV format, see
9297  // http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf.
9298  // Technically, this function returns the header and a metadata FLV tag
9299  // if duration is greater than zero
9300  // duration in seconds
9301  // @return {object} the bytes of the FLV header as a Uint8Array
9302  this.getFlvHeader = function(duration, audio, video) { // :ByteArray {
9303    var
9304      headBytes = new Uint8Array(3 + 1 + 1 + 4),
9305      head = new DataView(headBytes.buffer),
9306      metadata,
9307      result,
9308      metadataLength;
9309
9310    // default arguments
9311    duration = duration || 0;
9312    audio = audio === undefined ? true : audio;
9313    video = video === undefined ? true : video;
9314
9315    // signature
9316    head.setUint8(0, 0x46); // 'F'
9317    head.setUint8(1, 0x4c); // 'L'
9318    head.setUint8(2, 0x56); // 'V'
9319
9320    // version
9321    head.setUint8(3, 0x01);
9322
9323    // flags
9324    head.setUint8(4, (audio ? 0x04 : 0x00) | (video ? 0x01 : 0x00));
9325
9326    // data offset, should be 9 for FLV v1
9327    head.setUint32(5, headBytes.byteLength);
9328
9329    // init the first FLV tag
9330    if (duration <= 0) {
9331      // no duration available so just write the first field of the first
9332      // FLV tag
9333      result = new Uint8Array(headBytes.byteLength + 4);
9334      result.set(headBytes);
9335      result.set([0, 0, 0, 0], headBytes.byteLength);
9336      return result;
9337    }
9338
9339    // write out the duration metadata tag
9340    metadata = new FlvTag(FlvTag.METADATA_TAG);
9341    metadata.pts = metadata.dts = 0;
9342    metadata.writeMetaDataDouble('duration', duration);
9343    metadataLength = metadata.finalize().length;
9344    result = new Uint8Array(headBytes.byteLength + metadataLength);
9345    result.set(headBytes);
9346    result.set(head.byteLength, metadataLength);
9347
9348    return result;
9349  };
9350};
9351Transmuxer.prototype = new Stream();
9352
9353// forward compatibility
9354module.exports = Transmuxer;
9355
9356},{"../codecs/adts.js":68,"../codecs/h264":69,"../m2ts/m2ts.js":74,"../utils/stream.js":83,"./flv-tag.js":70}],73:[function(require,module,exports){
9357/**
9358 * mux.js
9359 *
9360 * Copyright (c) 2015 Brightcove
9361 * All rights reserved.
9362 *
9363 * Reads in-band caption information from a video elementary
9364 * stream. Captions must follow the CEA-708 standard for injection
9365 * into an MPEG-2 transport streams.
9366 * @see https://en.wikipedia.org/wiki/CEA-708
9367 */
9368
9369'use strict';
9370
9371// -----------------
9372// Link To Transport
9373// -----------------
9374
9375// Supplemental enhancement information (SEI) NAL units have a
9376// payload type field to indicate how they are to be
9377// interpreted. CEAS-708 caption content is always transmitted with
9378// payload type 0x04.
9379var USER_DATA_REGISTERED_ITU_T_T35 = 4,
9380    RBSP_TRAILING_BITS = 128,
9381    Stream = require('../utils/stream');
9382
9383/**
9384  * Parse a supplemental enhancement information (SEI) NAL unit.
9385  * Stops parsing once a message of type ITU T T35 has been found.
9386  *
9387  * @param bytes {Uint8Array} the bytes of a SEI NAL unit
9388  * @return {object} the parsed SEI payload
9389  * @see Rec. ITU-T H.264, 7.3.2.3.1
9390  */
9391var parseSei = function(bytes) {
9392  var
9393    i = 0,
9394    result = {
9395      payloadType: -1,
9396      payloadSize: 0
9397    },
9398    payloadType = 0,
9399    payloadSize = 0;
9400
9401  // go through the sei_rbsp parsing each each individual sei_message
9402  while (i < bytes.byteLength) {
9403    // stop once we have hit the end of the sei_rbsp
9404    if (bytes[i] === RBSP_TRAILING_BITS) {
9405      break;
9406    }
9407
9408    // Parse payload type
9409    while (bytes[i] === 0xFF) {
9410      payloadType += 255;
9411      i++;
9412    }
9413    payloadType += bytes[i++];
9414
9415    // Parse payload size
9416    while (bytes[i] === 0xFF) {
9417      payloadSize += 255;
9418      i++;
9419    }
9420    payloadSize += bytes[i++];
9421
9422    // this sei_message is a 608/708 caption so save it and break
9423    // there can only ever be one caption message in a frame's sei
9424    if (!result.payload && payloadType === USER_DATA_REGISTERED_ITU_T_T35) {
9425      result.payloadType = payloadType;
9426      result.payloadSize = payloadSize;
9427      result.payload = bytes.subarray(i, i + payloadSize);
9428      break;
9429    }
9430
9431    // skip the payload and parse the next message
9432    i += payloadSize;
9433    payloadType = 0;
9434    payloadSize = 0;
9435  }
9436
9437  return result;
9438};
9439
9440// see ANSI/SCTE 128-1 (2013), section 8.1
9441var parseUserData = function(sei) {
9442  // itu_t_t35_contry_code must be 181 (United States) for
9443  // captions
9444  if (sei.payload[0] !== 181) {
9445    return null;
9446  }
9447
9448  // itu_t_t35_provider_code should be 49 (ATSC) for captions
9449  if (((sei.payload[1] << 8) | sei.payload[2]) !== 49) {
9450    return null;
9451  }
9452
9453  // the user_identifier should be "GA94" to indicate ATSC1 data
9454  if (String.fromCharCode(sei.payload[3],
9455                          sei.payload[4],
9456                          sei.payload[5],
9457                          sei.payload[6]) !== 'GA94') {
9458    return null;
9459  }
9460
9461  // finally, user_data_type_code should be 0x03 for caption data
9462  if (sei.payload[7] !== 0x03) {
9463    return null;
9464  }
9465
9466  // return the user_data_type_structure and strip the trailing
9467  // marker bits
9468  return sei.payload.subarray(8, sei.payload.length - 1);
9469};
9470
9471// see CEA-708-D, section 4.4
9472var parseCaptionPackets = function(pts, userData) {
9473  var results = [], i, count, offset, data;
9474
9475  // if this is just filler, return immediately
9476  if (!(userData[0] & 0x40)) {
9477    return results;
9478  }
9479
9480  // parse out the cc_data_1 and cc_data_2 fields
9481  count = userData[0] & 0x1f;
9482  for (i = 0; i < count; i++) {
9483    offset = i * 3;
9484    data = {
9485      type: userData[offset + 2] & 0x03,
9486      pts: pts
9487    };
9488
9489    // capture cc data when cc_valid is 1
9490    if (userData[offset + 2] & 0x04) {
9491      data.ccData = (userData[offset + 3] << 8) | userData[offset + 4];
9492      results.push(data);
9493    }
9494  }
9495  return results;
9496};
9497
9498var CaptionStream = function() {
9499  CaptionStream.prototype.init.call(this);
9500
9501  this.captionPackets_ = [];
9502
9503  this.field1_ = new Cea608Stream(); // eslint-disable-line no-use-before-define
9504
9505  // forward data and done events from field1_ to this CaptionStream
9506  this.field1_.on('data', this.trigger.bind(this, 'data'));
9507  this.field1_.on('done', this.trigger.bind(this, 'done'));
9508};
9509CaptionStream.prototype = new Stream();
9510CaptionStream.prototype.push = function(event) {
9511  var sei, userData;
9512
9513  // only examine SEI NALs
9514  if (event.nalUnitType !== 'sei_rbsp') {
9515    return;
9516  }
9517
9518  // parse the sei
9519  sei = parseSei(event.escapedRBSP);
9520
9521  // ignore everything but user_data_registered_itu_t_t35
9522  if (sei.payloadType !== USER_DATA_REGISTERED_ITU_T_T35) {
9523    return;
9524  }
9525
9526  // parse out the user data payload
9527  userData = parseUserData(sei);
9528
9529  // ignore unrecognized userData
9530  if (!userData) {
9531    return;
9532  }
9533
9534  // parse out CC data packets and save them for later
9535  this.captionPackets_ = this.captionPackets_.concat(parseCaptionPackets(event.pts, userData));
9536};
9537
9538CaptionStream.prototype.flush = function() {
9539  // make sure we actually parsed captions before proceeding
9540  if (!this.captionPackets_.length) {
9541    this.field1_.flush();
9542    return;
9543  }
9544
9545  // In Chrome, the Array#sort function is not stable so add a
9546  // presortIndex that we can use to ensure we get a stable-sort
9547  this.captionPackets_.forEach(function(elem, idx) {
9548    elem.presortIndex = idx;
9549  });
9550
9551  // sort caption byte-pairs based on their PTS values
9552  this.captionPackets_.sort(function(a, b) {
9553    if (a.pts === b.pts) {
9554      return a.presortIndex - b.presortIndex;
9555    }
9556    return a.pts - b.pts;
9557  });
9558
9559  // Push each caption into Cea608Stream
9560  this.captionPackets_.forEach(this.field1_.push, this.field1_);
9561
9562  this.captionPackets_.length = 0;
9563  this.field1_.flush();
9564  return;
9565};
9566// ----------------------
9567// Session to Application
9568// ----------------------
9569
9570var BASIC_CHARACTER_TRANSLATION = {
9571  0x2a: 0xe1,
9572  0x5c: 0xe9,
9573  0x5e: 0xed,
9574  0x5f: 0xf3,
9575  0x60: 0xfa,
9576  0x7b: 0xe7,
9577  0x7c: 0xf7,
9578  0x7d: 0xd1,
9579  0x7e: 0xf1,
9580  0x7f: 0x2588
9581};
9582
9583var getCharFromCode = function(code) {
9584  if (code === null) {
9585    return '';
9586  }
9587  code = BASIC_CHARACTER_TRANSLATION[code] || code;
9588  return String.fromCharCode(code);
9589};
9590
9591// Constants for the byte codes recognized by Cea608Stream. This
9592// list is not exhaustive. For a more comprehensive listing and
9593// semantics see
9594// http://www.gpo.gov/fdsys/pkg/CFR-2010-title47-vol1/pdf/CFR-2010-title47-vol1-sec15-119.pdf
9595var PADDING                    = 0x0000,
9596
9597    // Pop-on Mode
9598    RESUME_CAPTION_LOADING     = 0x1420,
9599    END_OF_CAPTION             = 0x142f,
9600
9601    // Roll-up Mode
9602    ROLL_UP_2_ROWS             = 0x1425,
9603    ROLL_UP_3_ROWS             = 0x1426,
9604    ROLL_UP_4_ROWS             = 0x1427,
9605    CARRIAGE_RETURN            = 0x142d,
9606    // Erasure
9607    BACKSPACE                  = 0x1421,
9608    ERASE_DISPLAYED_MEMORY     = 0x142c,
9609    ERASE_NON_DISPLAYED_MEMORY = 0x142e;
9610
9611// the index of the last row in a CEA-608 display buffer
9612var BOTTOM_ROW = 14;
9613// CEA-608 captions are rendered onto a 34x15 matrix of character
9614// cells. The "bottom" row is the last element in the outer array.
9615var createDisplayBuffer = function() {
9616  var result = [], i = BOTTOM_ROW + 1;
9617  while (i--) {
9618    result.push('');
9619  }
9620  return result;
9621};
9622
9623var Cea608Stream = function() {
9624  Cea608Stream.prototype.init.call(this);
9625
9626  this.mode_ = 'popOn';
9627  // When in roll-up mode, the index of the last row that will
9628  // actually display captions. If a caption is shifted to a row
9629  // with a lower index than this, it is cleared from the display
9630  // buffer
9631  this.topRow_ = 0;
9632  this.startPts_ = 0;
9633  this.displayed_ = createDisplayBuffer();
9634  this.nonDisplayed_ = createDisplayBuffer();
9635  this.lastControlCode_ = null;
9636
9637  this.push = function(packet) {
9638    // Ignore other channels
9639    if (packet.type !== 0) {
9640      return;
9641    }
9642    var data, swap, char0, char1;
9643    // remove the parity bits
9644    data = packet.ccData & 0x7f7f;
9645
9646    // ignore duplicate control codes
9647    if (data === this.lastControlCode_) {
9648      this.lastControlCode_ = null;
9649      return;
9650    }
9651
9652    // Store control codes
9653    if ((data & 0xf000) === 0x1000) {
9654      this.lastControlCode_ = data;
9655    } else {
9656      this.lastControlCode_ = null;
9657    }
9658
9659    switch (data) {
9660    case PADDING:
9661      break;
9662    case RESUME_CAPTION_LOADING:
9663      this.mode_ = 'popOn';
9664      break;
9665    case END_OF_CAPTION:
9666      // if a caption was being displayed, it's gone now
9667      this.flushDisplayed(packet.pts);
9668
9669      // flip memory
9670      swap = this.displayed_;
9671      this.displayed_ = this.nonDisplayed_;
9672      this.nonDisplayed_ = swap;
9673
9674      // start measuring the time to display the caption
9675      this.startPts_ = packet.pts;
9676      break;
9677
9678    case ROLL_UP_2_ROWS:
9679      this.topRow_ = BOTTOM_ROW - 1;
9680      this.mode_ = 'rollUp';
9681      break;
9682    case ROLL_UP_3_ROWS:
9683      this.topRow_ = BOTTOM_ROW - 2;
9684      this.mode_ = 'rollUp';
9685      break;
9686    case ROLL_UP_4_ROWS:
9687      this.topRow_ = BOTTOM_ROW - 3;
9688      this.mode_ = 'rollUp';
9689      break;
9690    case CARRIAGE_RETURN:
9691      this.flushDisplayed(packet.pts);
9692      this.shiftRowsUp_();
9693      this.startPts_ = packet.pts;
9694      break;
9695
9696    case BACKSPACE:
9697      if (this.mode_ === 'popOn') {
9698        this.nonDisplayed_[BOTTOM_ROW] = this.nonDisplayed_[BOTTOM_ROW].slice(0, -1);
9699      } else {
9700        this.displayed_[BOTTOM_ROW] = this.displayed_[BOTTOM_ROW].slice(0, -1);
9701      }
9702      break;
9703    case ERASE_DISPLAYED_MEMORY:
9704      this.flushDisplayed(packet.pts);
9705      this.displayed_ = createDisplayBuffer();
9706      break;
9707    case ERASE_NON_DISPLAYED_MEMORY:
9708      this.nonDisplayed_ = createDisplayBuffer();
9709      break;
9710    default:
9711      char0 = data >>> 8;
9712      char1 = data & 0xff;
9713
9714      // Look for a Channel 1 Preamble Address Code
9715      if (char0 >= 0x10 && char0 <= 0x17 &&
9716          char1 >= 0x40 && char1 <= 0x7F &&
9717          (char0 !== 0x10 || char1 < 0x60)) {
9718        // Follow Safari's lead and replace the PAC with a space
9719        char0 = 0x20;
9720        // we only want one space so make the second character null
9721        // which will get become '' in getCharFromCode
9722        char1 = null;
9723      }
9724
9725      // Look for special character sets
9726      if ((char0 === 0x11 || char0 === 0x19) &&
9727          (char1 >= 0x30 && char1 <= 0x3F)) {
9728        // Put in eigth note and space
9729        char0 = 0x266A;
9730        char1 = '';
9731      }
9732
9733      // ignore unsupported control codes
9734      if ((char0 & 0xf0) === 0x10) {
9735        return;
9736      }
9737
9738      // character handling is dependent on the current mode
9739      this[this.mode_](packet.pts, char0, char1);
9740      break;
9741    }
9742  };
9743};
9744Cea608Stream.prototype = new Stream();
9745// Trigger a cue point that captures the current state of the
9746// display buffer
9747Cea608Stream.prototype.flushDisplayed = function(pts) {
9748  var content = this.displayed_
9749    // remove spaces from the start and end of the string
9750    .map(function(row) {
9751      return row.trim();
9752    })
9753    // remove empty rows
9754    .filter(function(row) {
9755      return row.length;
9756    })
9757    // combine all text rows to display in one cue
9758    .join('\n');
9759
9760  if (content.length) {
9761    this.trigger('data', {
9762      startPts: this.startPts_,
9763      endPts: pts,
9764      text: content
9765    });
9766  }
9767};
9768
9769// Mode Implementations
9770Cea608Stream.prototype.popOn = function(pts, char0, char1) {
9771  var baseRow = this.nonDisplayed_[BOTTOM_ROW];
9772
9773  // buffer characters
9774  baseRow += getCharFromCode(char0);
9775  baseRow += getCharFromCode(char1);
9776  this.nonDisplayed_[BOTTOM_ROW] = baseRow;
9777};
9778
9779Cea608Stream.prototype.rollUp = function(pts, char0, char1) {
9780  var baseRow = this.displayed_[BOTTOM_ROW];
9781  if (baseRow === '') {
9782    // we're starting to buffer new display input, so flush out the
9783    // current display
9784    this.flushDisplayed(pts);
9785
9786    this.startPts_ = pts;
9787  }
9788
9789  baseRow += getCharFromCode(char0);
9790  baseRow += getCharFromCode(char1);
9791
9792  this.displayed_[BOTTOM_ROW] = baseRow;
9793};
9794Cea608Stream.prototype.shiftRowsUp_ = function() {
9795  var i;
9796  // clear out inactive rows
9797  for (i = 0; i < this.topRow_; i++) {
9798    this.displayed_[i] = '';
9799  }
9800  // shift displayed rows up
9801  for (i = this.topRow_; i < BOTTOM_ROW; i++) {
9802    this.displayed_[i] = this.displayed_[i + 1];
9803  }
9804  // clear out the bottom row
9805  this.displayed_[BOTTOM_ROW] = '';
9806};
9807
9808// exports
9809module.exports = {
9810  CaptionStream: CaptionStream,
9811  Cea608Stream: Cea608Stream
9812};
9813
9814},{"../utils/stream":83}],74:[function(require,module,exports){
9815/**
9816 * mux.js
9817 *
9818 * Copyright (c) 2015 Brightcove
9819 * All rights reserved.
9820 *
9821 * A stream-based mp2t to mp4 converter. This utility can be used to
9822 * deliver mp4s to a SourceBuffer on platforms that support native
9823 * Media Source Extensions.
9824 */
9825'use strict';
9826var Stream = require('../utils/stream.js'),
9827  CaptionStream = require('./caption-stream'),
9828  StreamTypes = require('./stream-types'),
9829  TimestampRolloverStream = require('./timestamp-rollover-stream').TimestampRolloverStream;
9830
9831var m2tsStreamTypes = require('./stream-types.js');
9832
9833// object types
9834var TransportPacketStream, TransportParseStream, ElementaryStream;
9835
9836// constants
9837var
9838  MP2T_PACKET_LENGTH = 188, // bytes
9839  SYNC_BYTE = 0x47;
9840
9841/**
9842 * Splits an incoming stream of binary data into MPEG-2 Transport
9843 * Stream packets.
9844 */
9845TransportPacketStream = function() {
9846  var
9847    buffer = new Uint8Array(MP2T_PACKET_LENGTH),
9848    bytesInBuffer = 0;
9849
9850  TransportPacketStream.prototype.init.call(this);
9851
9852   // Deliver new bytes to the stream.
9853
9854  this.push = function(bytes) {
9855    var
9856      startIndex = 0,
9857      endIndex = MP2T_PACKET_LENGTH,
9858      everything;
9859
9860    // If there are bytes remaining from the last segment, prepend them to the
9861    // bytes that were pushed in
9862    if (bytesInBuffer) {
9863      everything = new Uint8Array(bytes.byteLength + bytesInBuffer);
9864      everything.set(buffer.subarray(0, bytesInBuffer));
9865      everything.set(bytes, bytesInBuffer);
9866      bytesInBuffer = 0;
9867    } else {
9868      everything = bytes;
9869    }
9870
9871    // While we have enough data for a packet
9872    while (endIndex < everything.byteLength) {
9873      // Look for a pair of start and end sync bytes in the data..
9874      if (everything[startIndex] === SYNC_BYTE && everything[endIndex] === SYNC_BYTE) {
9875        // We found a packet so emit it and jump one whole packet forward in
9876        // the stream
9877        this.trigger('data', everything.subarray(startIndex, endIndex));
9878        startIndex += MP2T_PACKET_LENGTH;
9879        endIndex += MP2T_PACKET_LENGTH;
9880        continue;
9881      }
9882      // If we get here, we have somehow become de-synchronized and we need to step
9883      // forward one byte at a time until we find a pair of sync bytes that denote
9884      // a packet
9885      startIndex++;
9886      endIndex++;
9887    }
9888
9889    // If there was some data left over at the end of the segment that couldn't
vendor: 5,342 bytes, lines 9890-10038
9890    // possibly be a whole packet, keep it because it might be the start of a packet
9891    // that continues in the next segment
9892    if (startIndex < everything.byteLength) {
9893      buffer.set(everything.subarray(startIndex), 0);
9894      bytesInBuffer = everything.byteLength - startIndex;
9895    }
9896  };
9897
9898  this.flush = function() {
9899    // If the buffer contains a whole packet when we are being flushed, emit it
9900    // and empty the buffer. Otherwise hold onto the data because it may be
9901    // important for decoding the next segment
9902    if (bytesInBuffer === MP2T_PACKET_LENGTH && buffer[0] === SYNC_BYTE) {
9903      this.trigger('data', buffer);
9904      bytesInBuffer = 0;
9905    }
9906    this.trigger('done');
9907  };
9908};
9909TransportPacketStream.prototype = new Stream();
9910
9911/**
9912 * Accepts an MP2T TransportPacketStream and emits data events with parsed
9913 * forms of the individual transport stream packets.
9914 */
9915TransportParseStream = function() {
9916  var parsePsi, parsePat, parsePmt, self;
9917  TransportParseStream.prototype.init.call(this);
9918  self = this;
9919
9920  this.packetsWaitingForPmt = [];
9921  this.programMapTable = undefined;
9922
9923  parsePsi = function(payload, psi) {
9924    var offset = 0;
9925
9926    // PSI packets may be split into multiple sections and those
9927    // sections may be split into multiple packets. If a PSI
9928    // section starts in this packet, the payload_unit_start_indicator
9929    // will be true and the first byte of the payload will indicate
9930    // the offset from the current position to the start of the
9931    // section.
9932    if (psi.payloadUnitStartIndicator) {
9933      offset += payload[offset] + 1;
9934    }
9935
9936    if (psi.type === 'pat') {
9937      parsePat(payload.subarray(offset), psi);
9938    } else {
9939      parsePmt(payload.subarray(offset), psi);
9940    }
9941  };
9942
9943  parsePat = function(payload, pat) {
9944    pat.section_number = payload[7]; // eslint-disable-line camelcase
9945    pat.last_section_number = payload[8]; // eslint-disable-line camelcase
9946
9947    // skip the PSI header and parse the first PMT entry
9948    self.pmtPid = (payload[10] & 0x1F) << 8 | payload[11];
9949    pat.pmtPid = self.pmtPid;
9950  };
9951
9952  /**
9953   * Parse out the relevant fields of a Program Map Table (PMT).
9954   * @param payload {Uint8Array} the PMT-specific portion of an MP2T
9955   * packet. The first byte in this array should be the table_id
9956   * field.
9957   * @param pmt {object} the object that should be decorated with
9958   * fields parsed from the PMT.
9959   */
9960  parsePmt = function(payload, pmt) {
9961    var sectionLength, tableEnd, programInfoLength, offset;
9962
9963    // PMTs can be sent ahead of the time when they should actually
9964    // take effect. We don't believe this should ever be the case
9965    // for HLS but we'll ignore "forward" PMT declarations if we see
9966    // them. Future PMT declarations have the current_next_indicator
9967    // set to zero.
9968    if (!(payload[5] & 0x01)) {
9969      return;
9970    }
9971
9972    // overwrite any existing program map table
9973    self.programMapTable = {};
9974
9975    // the mapping table ends at the end of the current section
9976    sectionLength = (payload[1] & 0x0f) << 8 | payload[2];
9977    tableEnd = 3 + sectionLength - 4;
9978
9979    // to determine where the table is, we have to figure out how
9980    // long the program info descriptors are
9981    programInfoLength = (payload[10] & 0x0f) << 8 | payload[11];
9982
9983    // advance the offset to the first entry in the mapping table
9984    offset = 12 + programInfoLength;
9985    while (offset < tableEnd) {
9986      // add an entry that maps the elementary_pid to the stream_type
9987      self.programMapTable[(payload[offset + 1] & 0x1F) << 8 | payload[offset + 2]] = payload[offset];
9988
9989      // move to the next table entry
9990      // skip past the elementary stream descriptors, if present
9991      offset += ((payload[offset + 3] & 0x0F) << 8 | payload[offset + 4]) + 5;
9992    }
9993
9994    // record the map on the packet as well
9995    pmt.programMapTable = self.programMapTable;
9996
9997    // if there are any packets waiting for a PMT to be found, process them now
9998    while (self.packetsWaitingForPmt.length) {
9999      self.processPes_.apply(self, self.packetsWaitingForPmt.shift());
10000    }
10001  };
10002
10003  /**
10004   * Deliver a new MP2T packet to the stream.
10005   */
10006  this.push = function(packet) {
10007    var
10008      result = {},
10009      offset = 4;
10010
10011    result.payloadUnitStartIndicator = !!(packet[1] & 0x40);
10012
10013    // pid is a 13-bit field starting at the last bit of packet[1]
10014    result.pid = packet[1] & 0x1f;
10015    result.pid <<= 8;
10016    result.pid |= packet[2];
10017
10018    // if an adaption field is present, its length is specified by the
10019    // fifth byte of the TS packet header. The adaptation field is
10020    // used to add stuffing to PES packets that don't fill a complete
10021    // TS packet, and to specify some forms of timing and control data
10022    // that we do not currently use.
10023    if (((packet[3] & 0x30) >>> 4) > 0x01) {
10024      offset += packet[offset] + 1;
10025    }
10026
10027    // parse the rest of the packet based on the type
10028    if (result.pid === 0) {
10029      result.type = 'pat';
10030      parsePsi(packet.subarray(offset), result);
10031      this.trigger('data', result);
10032    } else if (result.pid === this.pmtPid) {
10033      result.type = 'pmt';
10034      parsePsi(packet.subarray(offset), result);
10035      this.trigger('data', result);
10036    } else if (this.programMapTable === undefined) {
10037      // When we have not seen a PMT yet, defer further processing of
10038      // PES packets until one has been parsed
10039      this.packetsWaitingForPmt.push([packet, offset, result]);
10040    } else {
10041      this.processPes_(packet, offset, result);
10042    }
10043  };
10044
10045  this.processPes_ = function(packet, offset, result) {
10046    result.streamType = this.programMapTable[result.pid];
10047    result.type = 'pes';
10048    result.data = packet.subarray(offset);
10049
10050    this.trigger('data', result);
10051  };
10052
10053};
10054TransportParseStream.prototype = new Stream();
10055TransportParseStream.STREAM_TYPES  = {
10056  h264: 0x1b,
10057  adts: 0x0f
10058};
10059
10060/**
10061 * Reconsistutes program elementary stream (PES) packets from parsed
10062 * transport stream packets. That is, if you pipe an
10063 * mp2t.TransportParseStream into a mp2t.ElementaryStream, the output
10064 * events will be events which capture the bytes for individual PES
10065 * packets plus relevant metadata that has been extracted from the
10066 * container.
10067 */
10068ElementaryStream = function() {
10069  var
10070    self = this,
10071    // PES packet fragments
10072    video = {
10073      data: [],
10074      size: 0
10075    },
10076    audio = {
10077      data: [],
10078      size: 0
10079    },
10080    timedMetadata = {
10081      data: [],
10082      size: 0
10083    },
10084    parsePes = function(payload, pes) {
10085      var ptsDtsFlags;
10086
10087      // find out if this packets starts a new keyframe
10088      pes.dataAlignmentIndicator = (payload[6] & 0x04) !== 0;
10089      // PES packets may be annotated with a PTS value, or a PTS value
10090      // and a DTS value. Determine what combination of values is
10091      // available to work with.
10092      ptsDtsFlags = payload[7];
10093
10094      // PTS and DTS are normally stored as a 33-bit number.  Javascript
10095      // performs all bitwise operations on 32-bit integers but javascript
10096      // supports a much greater range (52-bits) of integer using standard
10097      // mathematical operations.
10098      // We construct a 31-bit value using bitwise operators over the 31
10099      // most significant bits and then multiply by 4 (equal to a left-shift
10100      // of 2) before we add the final 2 least significant bits of the
10101      // timestamp (equal to an OR.)
10102      if (ptsDtsFlags & 0xC0) {
10103        // the PTS and DTS are not written out directly. For information
10104        // on how they are encoded, see
10105        // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
10106        pes.pts = (payload[9] & 0x0E) << 27 |
10107          (payload[10] & 0xFF) << 20 |
10108          (payload[11] & 0xFE) << 12 |
10109          (payload[12] & 0xFF) <<  5 |
10110          (payload[13] & 0xFE) >>>  3;
10111        pes.pts *= 4; // Left shift by 2
10112        pes.pts += (payload[13] & 0x06) >>> 1; // OR by the two LSBs
10113        pes.dts = pes.pts;
10114        if (ptsDtsFlags & 0x40) {
10115          pes.dts = (payload[14] & 0x0E) << 27 |
10116            (payload[15] & 0xFF) << 20 |
10117            (payload[16] & 0xFE) << 12 |
10118            (payload[17] & 0xFF) << 5 |
10119            (payload[18] & 0xFE) >>> 3;
10120          pes.dts *= 4; // Left shift by 2
10121          pes.dts += (payload[18] & 0x06) >>> 1; // OR by the two LSBs
10122        }
10123      }
10124      // the data section starts immediately after the PES header.
10125      // pes_header_data_length specifies the number of header bytes
10126      // that follow the last byte of the field.
10127      pes.data = payload.subarray(9 + payload[8]);
10128    },
10129    flushStream = function(stream, type) {
10130      var
10131        packetData = new Uint8Array(stream.size),
10132        event = {
10133          type: type
10134        },
10135        i = 0,
10136        fragment;
10137
10138      // do nothing if there is no buffered data
10139      if (!stream.data.length) {
10140        return;
10141      }
10142      event.trackId = stream.data[0].pid;
10143
10144      // reassemble the packet
10145      while (stream.data.length) {
10146        fragment = stream.data.shift();
10147
10148        packetData.set(fragment.data, i);
10149        i += fragment.data.byteLength;
10150      }
10151
10152      // parse assembled packet's PES header
10153      parsePes(packetData, event);
10154
10155      stream.size = 0;
10156
10157      self.trigger('data', event);
10158    };
10159
10160  ElementaryStream.prototype.init.call(this);
10161
10162  this.push = function(data) {
10163    ({
10164      pat: function() {
10165        // we have to wait for the PMT to arrive as well before we
10166        // have any meaningful metadata
10167      },
10168      pes: function() {
10169        var stream, streamType;
10170
10171        switch (data.streamType) {
10172        case StreamTypes.H264_STREAM_TYPE:
10173        case m2tsStreamTypes.H264_STREAM_TYPE:
10174          stream = video;
10175          streamType = 'video';
10176          break;
10177        case StreamTypes.ADTS_STREAM_TYPE:
10178          stream = audio;
10179          streamType = 'audio';
10180          break;
10181        case StreamTypes.METADATA_STREAM_TYPE:
10182          stream = timedMetadata;
10183          streamType = 'timed-metadata';
10184          break;
10185        default:
10186          // ignore unknown stream types
10187          return;
10188        }
10189
10190        // if a new packet is starting, we can flush the completed
10191        // packet
10192        if (data.payloadUnitStartIndicator) {
10193          flushStream(stream, streamType);
10194        }
10195
10196        // buffer this fragment until we are sure we've received the
10197        // complete payload
10198        stream.data.push(data);
10199        stream.size += data.data.byteLength;
10200      },
10201      pmt: function() {
10202        var
10203          event = {
10204            type: 'metadata',
10205            tracks: []
10206          },
10207          programMapTable = data.programMapTable,
10208          k,
10209          track;
10210
10211        // translate streams to tracks
10212        for (k in programMapTable) {
10213          if (programMapTable.hasOwnProperty(k)) {
10214            track = {
10215              timelineStartInfo: {
10216                baseMediaDecodeTime: 0
10217              }
10218            };
10219            track.id = +k;
10220            if (programMapTable[k] === m2tsStreamTypes.H264_STREAM_TYPE) {
10221              track.codec = 'avc';
10222              track.type = 'video';
10223            } else if (programMapTable[k] === m2tsStreamTypes.ADTS_STREAM_TYPE) {
10224              track.codec = 'adts';
10225              track.type = 'audio';
10226            }
10227            event.tracks.push(track);
10228          }
10229        }
10230        self.trigger('data', event);
10231      }
10232    })[data.type]();
10233  };
10234
10235  /**
10236   * Flush any remaining input. Video PES packets may be of variable
10237   * length. Normally, the start of a new video packet can trigger the
10238   * finalization of the previous packet. That is not possible if no
10239   * more video is forthcoming, however. In that case, some other
10240   * mechanism (like the end of the file) has to be employed. When it is
10241   * clear that no additional data is forthcoming, calling this method
10242   * will flush the buffered packets.
10243   */
10244  this.flush = function() {
10245    // !!THIS ORDER IS IMPORTANT!!
10246    // video first then audio
10247    flushStream(video, 'video');
10248    flushStream(audio, 'audio');
10249    flushStream(timedMetadata, 'timed-metadata');
10250    this.trigger('done');
10251  };
10252};
10253ElementaryStream.prototype = new Stream();
10254
10255var m2ts = {
10256  PAT_PID: 0x0000,
10257  MP2T_PACKET_LENGTH: MP2T_PACKET_LENGTH,
vendor: 8,252 bytes, lines 10258-10504
10258  TransportPacketStream: TransportPacketStream,
10259  TransportParseStream: TransportParseStream,
10260  ElementaryStream: ElementaryStream,
10261  TimestampRolloverStream: TimestampRolloverStream,
10262  CaptionStream: CaptionStream.CaptionStream,
10263  Cea608Stream: CaptionStream.Cea608Stream,
10264  MetadataStream: require('./metadata-stream')
10265};
10266
10267for (var type in StreamTypes) {
10268  if (StreamTypes.hasOwnProperty(type)) {
10269    m2ts[type] = StreamTypes[type];
10270  }
10271}
10272
10273module.exports = m2ts;
10274
10275},{"../utils/stream.js":83,"./caption-stream":73,"./metadata-stream":75,"./stream-types":76,"./stream-types.js":76,"./timestamp-rollover-stream":77}],75:[function(require,module,exports){
10276/**
10277 * Accepts program elementary stream (PES) data events and parses out
10278 * ID3 metadata from them, if present.
10279 * @see http://id3.org/id3v2.3.0
10280 */
10281'use strict';
10282var
10283  Stream = require('../utils/stream'),
10284  StreamTypes = require('./stream-types'),
10285  // return a percent-encoded representation of the specified byte range
10286  // @see http://en.wikipedia.org/wiki/Percent-encoding
10287  percentEncode = function(bytes, start, end) {
10288    var i, result = '';
10289    for (i = start; i < end; i++) {
10290      result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
10291    }
10292    return result;
10293  },
10294  // return the string representation of the specified byte range,
10295  // interpreted as UTf-8.
10296  parseUtf8 = function(bytes, start, end) {
10297    return decodeURIComponent(percentEncode(bytes, start, end));
10298  },
10299  // return the string representation of the specified byte range,
10300  // interpreted as ISO-8859-1.
10301  parseIso88591 = function(bytes, start, end) {
10302    return unescape(percentEncode(bytes, start, end)); // jshint ignore:line
10303  },
10304  parseSyncSafeInteger = function(data) {
10305    return (data[0] << 21) |
10306            (data[1] << 14) |
10307            (data[2] << 7) |
10308            (data[3]);
10309  },
10310  tagParsers = {
10311    TXXX: function(tag) {
10312      var i;
10313      if (tag.data[0] !== 3) {
10314        // ignore frames with unrecognized character encodings
10315        return;
10316      }
10317
10318      for (i = 1; i < tag.data.length; i++) {
10319        if (tag.data[i] === 0) {
10320          // parse the text fields
10321          tag.description = parseUtf8(tag.data, 1, i);
10322          // do not include the null terminator in the tag value
10323          tag.value = parseUtf8(tag.data, i + 1, tag.data.length - 1);
10324          break;
10325        }
10326      }
10327      tag.data = tag.value;
10328    },
10329    WXXX: function(tag) {
10330      var i;
10331      if (tag.data[0] !== 3) {
10332        // ignore frames with unrecognized character encodings
10333        return;
10334      }
10335
10336      for (i = 1; i < tag.data.length; i++) {
10337        if (tag.data[i] === 0) {
10338          // parse the description and URL fields
10339          tag.description = parseUtf8(tag.data, 1, i);
10340          tag.url = parseUtf8(tag.data, i + 1, tag.data.length);
10341          break;
10342        }
10343      }
10344    },
10345    PRIV: function(tag) {
10346      var i;
10347
10348      for (i = 0; i < tag.data.length; i++) {
10349        if (tag.data[i] === 0) {
10350          // parse the description and URL fields
10351          tag.owner = parseIso88591(tag.data, 0, i);
10352          break;
10353        }
10354      }
10355      tag.privateData = tag.data.subarray(i + 1);
10356      tag.data = tag.privateData;
10357    }
10358  },
10359  MetadataStream;
10360
10361MetadataStream = function(options) {
10362  var
10363    settings = {
10364      debug: !!(options && options.debug),
10365
10366      // the bytes of the program-level descriptor field in MP2T
10367      // see ISO/IEC 13818-1:2013 (E), section 2.6 "Program and
10368      // program element descriptors"
10369      descriptor: options && options.descriptor
10370    },
10371    // the total size in bytes of the ID3 tag being parsed
10372    tagSize = 0,
10373    // tag data that is not complete enough to be parsed
10374    buffer = [],
10375    // the total number of bytes currently in the buffer
10376    bufferSize = 0,
10377    i;
10378
10379  MetadataStream.prototype.init.call(this);
10380
10381  // calculate the text track in-band metadata track dispatch type
10382  // https://html.spec.whatwg.org/multipage/embedded-content.html#steps-to-expose-a-media-resource-specific-text-track
10383  this.dispatchType = StreamTypes.METADATA_STREAM_TYPE.toString(16);
10384  if (settings.descriptor) {
10385    for (i = 0; i < settings.descriptor.length; i++) {
10386      this.dispatchType += ('00' + settings.descriptor[i].toString(16)).slice(-2);
10387    }
10388  }
10389
10390  this.push = function(chunk) {
10391    var tag, frameStart, frameSize, frame, i, frameHeader;
10392    if (chunk.type !== 'timed-metadata') {
10393      return;
10394    }
10395
10396    // if data_alignment_indicator is set in the PES header,
10397    // we must have the start of a new ID3 tag. Assume anything
10398    // remaining in the buffer was malformed and throw it out
10399    if (chunk.dataAlignmentIndicator) {
10400      bufferSize = 0;
10401      buffer.length = 0;
10402    }
10403
10404    // ignore events that don't look like ID3 data
10405    if (buffer.length === 0 &&
10406        (chunk.data.length < 10 ||
10407          chunk.data[0] !== 'I'.charCodeAt(0) ||
10408          chunk.data[1] !== 'D'.charCodeAt(0) ||
10409          chunk.data[2] !== '3'.charCodeAt(0))) {
10410      if (settings.debug) {
10411        // eslint-disable-next-line no-console
10412        console.log('Skipping unrecognized metadata packet');
10413      }
10414      return;
10415    }
10416
10417    // add this chunk to the data we've collected so far
10418
10419    buffer.push(chunk);
10420    bufferSize += chunk.data.byteLength;
10421
10422    // grab the size of the entire frame from the ID3 header
10423    if (buffer.length === 1) {
10424      // the frame size is transmitted as a 28-bit integer in the
10425      // last four bytes of the ID3 header.
10426      // The most significant bit of each byte is dropped and the
10427      // results concatenated to recover the actual value.
10428      tagSize = parseSyncSafeInteger(chunk.data.subarray(6, 10));
10429
10430      // ID3 reports the tag size excluding the header but it's more
10431      // convenient for our comparisons to include it
10432      tagSize += 10;
10433    }
10434
10435    // if the entire frame has not arrived, wait for more data
10436    if (bufferSize < tagSize) {
10437      return;
10438    }
10439
10440    // collect the entire frame so it can be parsed
10441    tag = {
10442      data: new Uint8Array(tagSize),
10443      frames: [],
10444      pts: buffer[0].pts,
10445      dts: buffer[0].dts
10446    };
10447    for (i = 0; i < tagSize;) {
10448      tag.data.set(buffer[0].data.subarray(0, tagSize - i), i);
10449      i += buffer[0].data.byteLength;
10450      bufferSize -= buffer[0].data.byteLength;
10451      buffer.shift();
10452    }
10453
10454    // find the start of the first frame and the end of the tag
10455    frameStart = 10;
10456    if (tag.data[5] & 0x40) {
10457      // advance the frame start past the extended header
10458      frameStart += 4; // header size field
10459      frameStart += parseSyncSafeInteger(tag.data.subarray(10, 14));
10460
10461      // clip any padding off the end
10462      tagSize -= parseSyncSafeInteger(tag.data.subarray(16, 20));
10463    }
10464
10465    // parse one or more ID3 frames
10466    // http://id3.org/id3v2.3.0#ID3v2_frame_overview
10467    do {
10468      // determine the number of bytes in this frame
10469      frameSize = parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
10470      if (frameSize < 1) {
10471         // eslint-disable-next-line no-console
10472        return console.log('Malformed ID3 frame encountered. Skipping metadata parsing.');
10473      }
10474      frameHeader = String.fromCharCode(tag.data[frameStart],
10475                                        tag.data[frameStart + 1],
10476                                        tag.data[frameStart + 2],
10477                                        tag.data[frameStart + 3]);
10478
10479
10480      frame = {
10481        id: frameHeader,
10482        data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)
10483      };
10484      frame.key = frame.id;
10485      if (tagParsers[frame.id]) {
10486        tagParsers[frame.id](frame);
10487
10488        // handle the special PRIV frame used to indicate the start
10489        // time for raw AAC data
10490        if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
10491          var
10492            d = frame.data,
10493            size = ((d[3] & 0x01)  << 30) |
10494                   (d[4]  << 22) |
10495                   (d[5] << 14) |
10496                   (d[6] << 6) |
10497                   (d[7] >>> 2);
10498
10499          size *= 4;
10500          size += d[7] & 0x03;
10501          frame.timeStamp = size;
10502          // in raw AAC, all subsequent data will be timestamped based
10503          // on the value of this frame
10504          // we couldn't have known the appropriate pts and dts before
10505          // parsing this ID3 tag so set those values now
10506          if (tag.pts === undefined && tag.dts === undefined) {
10507            tag.pts = frame.timeStamp;
10508            tag.dts = frame.timeStamp;
10509          }
10510          this.trigger('timestamp', frame);
10511        }
10512      }
10513      tag.frames.push(frame);
10514
10515      frameStart += 10; // advance past the frame header
10516      frameStart += frameSize; // advance past the frame body
10517    } while (frameStart < tagSize);
10518    this.trigger('data', tag);
10519  };
10520};
10521MetadataStream.prototype = new Stream();
10522
10523module.exports = MetadataStream;
10524
10525},{"../utils/stream":83,"./stream-types":76}],76:[function(require,module,exports){
10526'use strict';
10527
10528module.exports = {
10529  H264_STREAM_TYPE: 0x1B,
10530  ADTS_STREAM_TYPE: 0x0F,
10531  METADATA_STREAM_TYPE: 0x15
10532};
10533
10534},{}],77:[function(require,module,exports){
10535/**
10536 * mux.js
10537 *
10538 * Copyright (c) 2016 Brightcove
10539 * All rights reserved.
10540 *
10541 * Accepts program elementary stream (PES) data events and corrects
10542 * decode and presentation time stamps to account for a rollover
10543 * of the 33 bit value.
10544 */
10545
10546'use strict';
10547
10548var Stream = require('../utils/stream');
10549
10550var MAX_TS = 8589934592;
10551
10552var RO_THRESH = 4294967296;
10553
10554var handleRollover = function(value, reference) {
10555  var direction = 1;
10556
10557  if (value > reference) {
10558    // If the current timestamp value is greater than our reference timestamp and we detect a
10559    // timestamp rollover, this means the roll over is happening in the opposite direction.
10560    // Example scenario: Enter a long stream/video just after a rollover occurred. The reference
10561    // point will be set to a small number, e.g. 1. The user then seeks backwards over the
10562    // rollover point. In loading this segment, the timestamp values will be very large,
10563    // e.g. 2^33 - 1. Since this comes before the data we loaded previously, we want to adjust
10564    // the time stamp to be `value - 2^33`.
10565    direction = -1;
10566  }
10567
10568  // Note: A seek forwards or back that is greater than the RO_THRESH (2^32, ~13 hours) will
10569  // cause an incorrect adjustment.
10570  while (Math.abs(reference - value) > RO_THRESH) {
10571    value += (direction * MAX_TS);
10572  }
10573
10574  return value;
10575};
10576
10577var TimestampRolloverStream = function(type) {
10578  var lastDTS, referenceDTS;
10579
10580  TimestampRolloverStream.prototype.init.call(this);
10581
10582  this.type_ = type;
10583
10584  this.push = function(data) {
10585    if (data.type !== this.type_) {
10586      return;
10587    }
10588
10589    if (referenceDTS === undefined) {
10590      referenceDTS = data.dts;
10591    }
10592
10593    data.dts = handleRollover(data.dts, referenceDTS);
10594    data.pts = handleRollover(data.pts, referenceDTS);
10595
10596    lastDTS = data.dts;
10597
10598    this.trigger('data', data);
10599  };
10600
10601  this.flush = function() {
10602    referenceDTS = lastDTS;
10603    this.trigger('done');
10604  };
10605
10606};
10607
10608TimestampRolloverStream.prototype = new Stream();
10609
10610module.exports = {
10611  TimestampRolloverStream: TimestampRolloverStream,
10612  handleRollover: handleRollover
10613};
10614
10615},{"../utils/stream":83}],78:[function(require,module,exports){
10616module.exports = {
10617  generator: require('./mp4-generator'),
10618  Transmuxer: require('./transmuxer').Transmuxer,
10619  AudioSegmentStream: require('./transmuxer').AudioSegmentStream,
10620  VideoSegmentStream: require('./transmuxer').VideoSegmentStream
10621};
10622
10623},{"./mp4-generator":79,"./transmuxer":81}],79
vendor: 22,118 bytes, lines 10623-11395
10623:[function(require,module,exports){
10624/**
10625 * mux.js
10626 *
10627 * Copyright (c) 2015 Brightcove
10628 * All rights reserved.
10629 *
10630 * Functions that generate fragmented MP4s suitable for use with Media
10631 * Source Extensions.
10632 */
10633'use strict';
10634
10635var UINT32_MAX = Math.pow(2, 32) - 1;
10636
10637var box, dinf, esds, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd,
10638    trak, tkhd, mdia, mdhd, hdlr, sdtp, stbl, stsd, traf, trex,
10639    trun, types, MAJOR_BRAND, MINOR_VERSION, AVC1_BRAND, VIDEO_HDLR,
10640    AUDIO_HDLR, HDLR_TYPES, VMHD, SMHD, DREF, STCO, STSC, STSZ, STTS;
10641
10642// pre-calculate constants
10643(function() {
10644  var i;
10645  types = {
10646    avc1: [], // codingname
10647    avcC: [],
10648    btrt: [],
10649    dinf: [],
10650    dref: [],
10651    esds: [],
10652    ftyp: [],
10653    hdlr: [],
10654    mdat: [],
10655    mdhd: [],
10656    mdia: [],
10657    mfhd: [],
10658    minf: [],
10659    moof: [],
10660    moov: [],
10661    mp4a: [], // codingname
10662    mvex: [],
10663    mvhd: [],
10664    sdtp: [],
10665    smhd: [],
10666    stbl: [],
10667    stco: [],
10668    stsc: [],
10669    stsd: [],
10670    stsz: [],
10671    stts: [],
10672    styp: [],
10673    tfdt: [],
10674    tfhd: [],
10675    traf: [],
10676    trak: [],
10677    trun: [],
10678    trex: [],
10679    tkhd: [],
10680    vmhd: []
10681  };
10682
10683  // In environments where Uint8Array is undefined (e.g., IE8), skip set up so that we
10684  // don't throw an error
10685  if (typeof Uint8Array === 'undefined') {
10686    return;
10687  }
10688
10689  for (i in types) {
10690    if (types.hasOwnProperty(i)) {
10691      types[i] = [
10692        i.charCodeAt(0),
10693        i.charCodeAt(1),
10694        i.charCodeAt(2),
10695        i.charCodeAt(3)
10696      ];
10697    }
10698  }
10699
10700  MAJOR_BRAND = new Uint8Array([
10701    'i'.charCodeAt(0),
10702    's'.charCodeAt(0),
10703    'o'.charCodeAt(0),
10704    'm'.charCodeAt(0)
10705  ]);
10706  AVC1_BRAND = new Uint8Array([
10707    'a'.charCodeAt(0),
10708    'v'.charCodeAt(0),
10709    'c'.charCodeAt(0),
10710    '1'.charCodeAt(0)
10711  ]);
10712  MINOR_VERSION = new Uint8Array([0, 0, 0, 1]);
10713  VIDEO_HDLR = new Uint8Array([
10714    0x00, // version 0
10715    0x00, 0x00, 0x00, // flags
10716    0x00, 0x00, 0x00, 0x00, // pre_defined
10717    0x76, 0x69, 0x64, 0x65, // handler_type: 'vide'
10718    0x00, 0x00, 0x00, 0x00, // reserved
10719    0x00, 0x00, 0x00, 0x00, // reserved
10720    0x00, 0x00, 0x00, 0x00, // reserved
10721    0x56, 0x69, 0x64, 0x65,
10722    0x6f, 0x48, 0x61, 0x6e,
10723    0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'VideoHandler'
10724  ]);
10725  AUDIO_HDLR = new Uint8Array([
10726    0x00, // version 0
10727    0x00, 0x00, 0x00, // flags
10728    0x00, 0x00, 0x00, 0x00, // pre_defined
10729    0x73, 0x6f, 0x75, 0x6e, // handler_type: 'soun'
10730    0x00, 0x00, 0x00, 0x00, // reserved
10731    0x00, 0x00, 0x00, 0x00, // reserved
10732    0x00, 0x00, 0x00, 0x00, // reserved
10733    0x53, 0x6f, 0x75, 0x6e,
10734    0x64, 0x48, 0x61, 0x6e,
10735    0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'SoundHandler'
10736  ]);
10737  HDLR_TYPES = {
10738    video: VIDEO_HDLR,
10739    audio: AUDIO_HDLR
10740  };
10741  DREF = new Uint8Array([
10742    0x00, // version 0
10743    0x00, 0x00, 0x00, // flags
10744    0x00, 0x00, 0x00, 0x01, // entry_count
10745    0x00, 0x00, 0x00, 0x0c, // entry_size
10746    0x75, 0x72, 0x6c, 0x20, // 'url' type
10747    0x00, // version 0
10748    0x00, 0x00, 0x01 // entry_flags
10749  ]);
10750  SMHD = new Uint8Array([
10751    0x00,             // version
10752    0x00, 0x00, 0x00, // flags
10753    0x00, 0x00,       // balance, 0 means centered
10754    0x00, 0x00        // reserved
10755  ]);
10756  STCO = new Uint8Array([
10757    0x00, // version
10758    0x00, 0x00, 0x00, // flags
10759    0x00, 0x00, 0x00, 0x00 // entry_count
10760  ]);
10761  STSC = STCO;
10762  STSZ = new Uint8Array([
10763    0x00, // version
10764    0x00, 0x00, 0x00, // flags
10765    0x00, 0x00, 0x00, 0x00, // sample_size
10766    0x00, 0x00, 0x00, 0x00 // sample_count
10767  ]);
10768  STTS = STCO;
10769  VMHD = new Uint8Array([
10770    0x00, // version
10771    0x00, 0x00, 0x01, // flags
10772    0x00, 0x00, // graphicsmode
10773    0x00, 0x00,
10774    0x00, 0x00,
10775    0x00, 0x00 // opcolor
10776  ]);
10777}());
10778
10779box = function(type) {
10780  var
10781    payload = [],
10782    size = 0,
10783    i,
10784    result,
10785    view;
10786
10787  for (i = 1; i < arguments.length; i++) {
10788    payload.push(arguments[i]);
10789  }
10790
10791  i = payload.length;
10792
10793  // calculate the total size we need to allocate
10794  while (i--) {
10795    size += payload[i].byteLength;
10796  }
10797  result = new Uint8Array(size + 8);
10798  view = new DataView(result.buffer, result.byteOffset, result.byteLength);
10799  view.setUint32(0, result.byteLength);
10800  result.set(type, 4);
10801
10802  // copy the payload into the result
10803  for (i = 0, size = 8; i < payload.length; i++) {
10804    result.set(payload[i], size);
10805    size += payload[i].byteLength;
10806  }
10807  return result;
10808};
10809
10810dinf = function() {
10811  return box(types.dinf, box(types.dref, DREF));
10812};
10813
10814esds = function(track) {
10815  return box(types.esds, new Uint8Array([
10816    0x00, // version
10817    0x00, 0x00, 0x00, // flags
10818
10819    // ES_Descriptor
10820    0x03, // tag, ES_DescrTag
10821    0x19, // length
10822    0x00, 0x00, // ES_ID
10823    0x00, // streamDependenceFlag, URL_flag, reserved, streamPriority
10824
10825    // DecoderConfigDescriptor
10826    0x04, // tag, DecoderConfigDescrTag
10827    0x11, // length
10828    0x40, // object type
10829    0x15,  // streamType
10830    0x00, 0x06, 0x00, // bufferSizeDB
10831    0x00, 0x00, 0xda, 0xc0, // maxBitrate
10832    0x00, 0x00, 0xda, 0xc0, // avgBitrate
10833
10834    // DecoderSpecificInfo
10835    0x05, // tag, DecoderSpecificInfoTag
10836    0x02, // length
10837    // ISO/IEC 14496-3, AudioSpecificConfig
10838    // for samplingFrequencyIndex see ISO/IEC 13818-7:2006, 8.1.3.2.2, Table 35
10839    (track.audioobjecttype << 3) | (track.samplingfrequencyindex >>> 1),
10840    (track.samplingfrequencyindex << 7) | (track.channelcount << 3),
10841    0x06, 0x01, 0x02 // GASpecificConfig
10842  ]));
10843};
10844
10845ftyp = function() {
10846  return box(types.ftyp, MAJOR_BRAND, MINOR_VERSION, MAJOR_BRAND, AVC1_BRAND);
10847};
10848
10849hdlr = function(type) {
10850  return box(types.hdlr, HDLR_TYPES[type]);
10851};
10852mdat = function(data) {
10853  return box(types.mdat, data);
10854};
10855mdhd = function(track) {
10856  var result = new Uint8Array([
10857    0x00,                   // version 0
10858    0x00, 0x00, 0x00,       // flags
10859    0x00, 0x00, 0x00, 0x02, // creation_time
10860    0x00, 0x00, 0x00, 0x03, // modification_time
10861    0x00, 0x01, 0x5f, 0x90, // timescale, 90,000 "ticks" per second
10862
10863    (track.duration >>> 24) & 0xFF,
10864    (track.duration >>> 16) & 0xFF,
10865    (track.duration >>>  8) & 0xFF,
10866    track.duration & 0xFF,  // duration
10867    0x55, 0xc4,             // 'und' language (undetermined)
10868    0x00, 0x00
10869  ]);
10870
10871  // Use the sample rate from the track metadata, when it is
10872  // defined. The sample rate can be parsed out of an ADTS header, for
10873  // instance.
10874  if (track.samplerate) {
10875    result[12] = (track.samplerate >>> 24) & 0xFF;
10876    result[13] = (track.samplerate >>> 16) & 0xFF;
10877    result[14] = (track.samplerate >>>  8) & 0xFF;
10878    result[15] = (track.samplerate)        & 0xFF;
10879  }
10880
10881  return box(types.mdhd, result);
10882};
10883mdia = function(track) {
10884  return box(types.mdia, mdhd(track), hdlr(track.type), minf(track));
10885};
10886mfhd = function(sequenceNumber) {
10887  return box(types.mfhd, new Uint8Array([
10888    0x00,
10889    0x00, 0x00, 0x00, // flags
10890    (sequenceNumber & 0xFF000000) >> 24,
10891    (sequenceNumber & 0xFF0000) >> 16,
10892    (sequenceNumber & 0xFF00) >> 8,
10893    sequenceNumber & 0xFF // sequence_number
10894  ]));
10895};
10896minf = function(track) {
10897  return box(types.minf,
10898             track.type === 'video' ? box(types.vmhd, VMHD) : box(types.smhd, SMHD),
10899             dinf(),
10900             stbl(track));
10901};
10902moof = function(sequenceNumber, tracks) {
10903  var
10904    trackFragments = [],
10905    i = tracks.length;
10906  // build traf boxes for each track fragment
10907  while (i--) {
10908    trackFragments[i] = traf(tracks[i]);
10909  }
10910  return box.apply(null, [
10911    types.moof,
10912    mfhd(sequenceNumber)
10913  ].concat(trackFragments));
10914};
10915/**
10916 * Returns a movie box.
10917 * @param tracks {array} the tracks associated with this movie
10918 * @see ISO/IEC 14496-12:2012(E), section 8.2.1
10919 */
10920moov = function(tracks) {
10921  var
10922    i = tracks.length,
10923    boxes = [];
10924
10925  while (i--) {
10926    boxes[i] = trak(tracks[i]);
10927  }
10928
10929  return box.apply(null, [types.moov, mvhd(0xffffffff)].concat(boxes).concat(mvex(tracks)));
10930};
10931mvex = function(tracks) {
10932  var
10933    i = tracks.length,
10934    boxes = [];
10935
10936  while (i--) {
10937    boxes[i] = trex(tracks[i]);
10938  }
10939  return box.apply(null, [types.mvex].concat(boxes));
10940};
10941mvhd = function(duration) {
10942  var
10943    bytes = new Uint8Array([
10944      0x00, // version 0
10945      0x00, 0x00, 0x00, // flags
10946      0x00, 0x00, 0x00, 0x01, // creation_time
10947      0x00, 0x00, 0x00, 0x02, // modification_time
10948      0x00, 0x01, 0x5f, 0x90, // timescale, 90,000 "ticks" per second
10949      (duration & 0xFF000000) >> 24,
10950      (duration & 0xFF0000) >> 16,
10951      (duration & 0xFF00) >> 8,
10952      duration & 0xFF, // duration
10953      0x00, 0x01, 0x00, 0x00, // 1.0 rate
10954      0x01, 0x00, // 1.0 volume
10955      0x00, 0x00, // reserved
10956      0x00, 0x00, 0x00, 0x00, // reserved
10957      0x00, 0x00, 0x00, 0x00, // reserved
10958      0x00, 0x01, 0x00, 0x00,
10959      0x00, 0x00, 0x00, 0x00,
10960      0x00, 0x00, 0x00, 0x00,
10961      0x00, 0x00, 0x00, 0x00,
10962      0x00, 0x01, 0x00, 0x00,
10963      0x00, 0x00, 0x00, 0x00,
10964      0x00, 0x00, 0x00, 0x00,
10965      0x00, 0x00, 0x00, 0x00,
10966      0x40, 0x00, 0x00, 0x00, // transformation: unity matrix
10967      0x00, 0x00, 0x00, 0x00,
10968      0x00, 0x00, 0x00, 0x00,
10969      0x00, 0x00, 0x00, 0x00,
10970      0x00, 0x00, 0x00, 0x00,
10971      0x00, 0x00, 0x00, 0x00,
10972      0x00, 0x00, 0x00, 0x00, // pre_defined
10973      0xff, 0xff, 0xff, 0xff // next_track_ID
10974    ]);
10975  return box(types.mvhd, bytes);
10976};
10977
10978sdtp = function(track) {
10979  var
10980    samples = track.samples || [],
10981    bytes = new Uint8Array(4 + samples.length),
10982    flags,
10983    i;
10984
10985  // leave the full box header (4 bytes) all zero
10986
10987  // write the sample table
10988  for (i = 0; i < samples.length; i++) {
10989    flags = samples[i].flags;
10990
10991    bytes[i + 4] = (flags.dependsOn << 4) |
10992      (flags.isDependedOn << 2) |
10993      (flags.hasRedundancy);
10994  }
10995
10996  return box(types.sdtp,
10997             bytes);
10998};
10999
11000stbl = function(track) {
11001  return box(types.stbl,
11002             stsd(track),
11003             box(types.stts, STTS),
11004             box(types.stsc, STSC),
11005             box(types.stsz, STSZ),
11006             box(types.stco, STCO));
11007};
11008
11009(function() {
11010  var videoSample, audioSample;
11011
11012  stsd = function(track) {
11013
11014    return box(types.stsd, new Uint8Array([
11015      0x00, // version 0
11016      0x00, 0x00, 0x00, // flags
11017      0x00, 0x00, 0x00, 0x01
11018    ]), track.type === 'video' ? videoSample(track) : audioSample(track));
11019  };
11020
11021  videoSample = function(track) {
11022    var
11023      sps = track.sps || [],
11024      pps = track.pps || [],
11025      sequenceParameterSets = [],
11026      pictureParameterSets = [],
11027      i;
11028
11029    // assemble the SPSs
11030    for (i = 0; i < sps.length; i++) {
11031      sequenceParameterSets.push((sps[i].byteLength & 0xFF00) >>> 8);
11032      sequenceParameterSets.push((sps[i].byteLength & 0xFF)); // sequenceParameterSetLength
11033      sequenceParameterSets = sequenceParameterSets.concat(Array.prototype.slice.call(sps[i])); // SPS
11034    }
11035
11036    // assemble the PPSs
11037    for (i = 0; i < pps.length; i++) {
11038      pictureParameterSets.push((pps[i].byteLength & 0xFF00) >>> 8);
11039      pictureParameterSets.push((pps[i].byteLength & 0xFF));
11040      pictureParameterSets = pictureParameterSets.concat(Array.prototype.slice.call(pps[i]));
11041    }
11042
11043    return box(types.avc1, new Uint8Array([
11044      0x00, 0x00, 0x00,
11045      0x00, 0x00, 0x00, // reserved
11046      0x00, 0x01, // data_reference_index
11047      0x00, 0x00, // pre_defined
11048      0x00, 0x00, // reserved
11049      0x00, 0x00, 0x00, 0x00,
11050      0x00, 0x00, 0x00, 0x00,
11051      0x00, 0x00, 0x00, 0x00, // pre_defined
11052      (track.width & 0xff00) >> 8,
11053      track.width & 0xff, // width
11054      (track.height & 0xff00) >> 8,
11055      track.height & 0xff, // height
11056      0x00, 0x48, 0x00, 0x00, // horizresolution
11057      0x00, 0x48, 0x00, 0x00, // vertresolution
11058      0x00, 0x00, 0x00, 0x00, // reserved
11059      0x00, 0x01, // frame_count
11060      0x13,
11061      0x76, 0x69, 0x64, 0x65,
11062      0x6f, 0x6a, 0x73, 0x2d,
11063      0x63, 0x6f, 0x6e, 0x74,
11064      0x72, 0x69, 0x62, 0x2d,
11065      0x68, 0x6c, 0x73, 0x00,
11066      0x00, 0x00, 0x00, 0x00,
11067      0x00, 0x00, 0x00, 0x00,
11068      0x00, 0x00, 0x00, // compressorname
11069      0x00, 0x18, // depth = 24
11070      0x11, 0x11 // pre_defined = -1
11071    ]), box(types.avcC, new Uint8Array([
11072      0x01, // configurationVersion
11073      track.profileIdc, // AVCProfileIndication
11074      track.profileCompatibility, // profile_compatibility
11075      track.levelIdc, // AVCLevelIndication
11076      0xff // lengthSizeMinusOne, hard-coded to 4 bytes
11077    ].concat([
11078      sps.length // numOfSequenceParameterSets
11079    ]).concat(sequenceParameterSets).concat([
11080      pps.length // numOfPictureParameterSets
11081    ]).concat(pictureParameterSets))), // "PPS"
11082            box(types.btrt, new Uint8Array([
11083              0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB
11084              0x00, 0x2d, 0xc6, 0xc0, // maxBitrate
11085              0x00, 0x2d, 0xc6, 0xc0
11086            ])) // avgBitrate
11087              );
11088  };
11089
11090  audioSample = function(track) {
11091    return box(types.mp4a, new Uint8Array([
11092
11093      // SampleEntry, ISO/IEC 14496-12
11094      0x00, 0x00, 0x00,
11095      0x00, 0x00, 0x00, // reserved
11096      0x00, 0x01, // data_reference_index
11097
11098      // AudioSampleEntry, ISO/IEC 14496-12
11099      0x00, 0x00, 0x00, 0x00, // reserved
11100      0x00, 0x00, 0x00, 0x00, // reserved
11101      (track.channelcount & 0xff00) >> 8,
11102      (track.channelcount & 0xff), // channelcount
11103
11104      (track.samplesize & 0xff00) >> 8,
11105      (track.samplesize & 0xff), // samplesize
11106      0x00, 0x00, // pre_defined
11107      0x00, 0x00, // reserved
11108
11109      (track.samplerate & 0xff00) >> 8,
11110      (track.samplerate & 0xff),
11111      0x00, 0x00 // samplerate, 16.16
11112
11113      // MP4AudioSampleEntry, ISO/IEC 14496-14
11114    ]), esds(track));
11115  };
11116}());
11117
11118tkhd = function(track) {
11119  var result = new Uint8Array([
11120    0x00, // version 0
11121    0x00, 0x00, 0x07, // flags
11122    0x00, 0x00, 0x00, 0x00, // creation_time
11123    0x00, 0x00, 0x00, 0x00, // modification_time
11124    (track.id & 0xFF000000) >> 24,
11125    (track.id & 0xFF0000) >> 16,
11126    (track.id & 0xFF00) >> 8,
11127    track.id & 0xFF, // track_ID
11128    0x00, 0x00, 0x00, 0x00, // reserved
11129    (track.duration & 0xFF000000) >> 24,
11130    (track.duration & 0xFF0000) >> 16,
11131    (track.duration & 0xFF00) >> 8,
11132    track.duration & 0xFF, // duration
11133    0x00, 0x00, 0x00, 0x00,
11134    0x00, 0x00, 0x00, 0x00, // reserved
11135    0x00, 0x00, // layer
11136    0x00, 0x00, // alternate_group
11137    0x01, 0x00, // non-audio track volume
11138    0x00, 0x00, // reserved
11139    0x00, 0x01, 0x00, 0x00,
11140    0x00, 0x00, 0x00, 0x00,
11141    0x00, 0x00, 0x00, 0x00,
11142    0x00, 0x00, 0x00, 0x00,
11143    0x00, 0x01, 0x00, 0x00,
11144    0x00, 0x00, 0x00, 0x00,
11145    0x00, 0x00, 0x00, 0x00,
11146    0x00, 0x00, 0x00, 0x00,
11147    0x40, 0x00, 0x00, 0x00, // transformation: unity matrix
11148    (track.width & 0xFF00) >> 8,
11149    track.width & 0xFF,
11150    0x00, 0x00, // width
11151    (track.height & 0xFF00) >> 8,
11152    track.height & 0xFF,
11153    0x00, 0x00 // height
11154  ]);
11155
11156  return box(types.tkhd, result);
11157};
11158
11159/**
11160 * Generate a track fragment (traf) box. A traf box collects metadata
11161 * about tracks in a movie fragment (moof) box.
11162 */
11163traf = function(track) {
11164  var trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun,
11165      sampleDependencyTable, dataOffset,
11166      upperWordBaseMediaDecodeTime, lowerWordBaseMediaDecodeTime;
11167
11168  trackFragmentHeader = box(types.tfhd, new Uint8Array([
11169    0x00, // version 0
11170    0x00, 0x00, 0x3a, // flags
11171    (track.id & 0xFF000000) >> 24,
11172    (track.id & 0xFF0000) >> 16,
11173    (track.id & 0xFF00) >> 8,
11174    (track.id & 0xFF), // track_ID
11175    0x00, 0x00, 0x00, 0x01, // sample_description_index
11176    0x00, 0x00, 0x00, 0x00, // default_sample_duration
11177    0x00, 0x00, 0x00, 0x00, // default_sample_size
11178    0x00, 0x00, 0x00, 0x00  // default_sample_flags
11179  ]));
11180
11181  upperWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime / (UINT32_MAX + 1));
11182  lowerWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime % (UINT32_MAX + 1));
11183
11184  trackFragmentDecodeTime = box(types.tfdt, new Uint8Array([
11185    0x01, // version 1
11186    0x00, 0x00, 0x00, // flags
11187    // baseMediaDecodeTime
11188    (upperWordBaseMediaDecodeTime >>> 24) & 0xFF,
11189    (upperWordBaseMediaDecodeTime >>> 16) & 0xFF,
11190    (upperWordBaseMediaDecodeTime >>>  8) & 0xFF,
11191    upperWordBaseMediaDecodeTime & 0xFF,
11192    (lowerWordBaseMediaDecodeTime >>> 24) & 0xFF,
11193    (lowerWordBaseMediaDecodeTime >>> 16) & 0xFF,
11194    (lowerWordBaseMediaDecodeTime >>>  8) & 0xFF,
11195    lowerWordBaseMediaDecodeTime & 0xFF
11196  ]));
11197
11198  // the data offset specifies the number of bytes from the start of
11199  // the containing moof to the first payload byte of the associated
11200  // mdat
11201  dataOffset = (32 + // tfhd
11202                20 + // tfdt
11203                8 +  // traf header
11204                16 + // mfhd
11205                8 +  // moof header
11206                8);  // mdat header
11207
11208  // audio tracks require less metadata
11209  if (track.type === 'audio') {
11210    trackFragmentRun = trun(track, dataOffset);
11211    return box(types.traf,
11212               trackFragmentHeader,
11213               trackFragmentDecodeTime,
11214               trackFragmentRun);
11215  }
11216
11217  // video tracks should contain an independent and disposable samples
11218  // box (sdtp)
11219  // generate one and adjust offsets to match
11220  sampleDependencyTable = sdtp(track);
11221  trackFragmentRun = trun(track,
11222                          sampleDependencyTable.length + dataOffset);
11223  return box(types.traf,
11224             trackFragmentHeader,
11225             trackFragmentDecodeTime,
11226             trackFragmentRun,
11227             sampleDependencyTable);
11228};
11229
11230/**
11231 * Generate a track box.
11232 * @param track {object} a track definition
11233 * @return {Uint8Array} the track box
11234 */
11235trak = function(track) {
11236  track.duration = track.duration || 0xffffffff;
11237  return box(types.trak,
11238             tkhd(track),
11239             mdia(track));
11240};
11241
11242trex = function(track) {
11243  var result = new Uint8Array([
11244    0x00, // version 0
11245    0x00, 0x00, 0x00, // flags
11246    (track.id & 0xFF000000) >> 24,
11247    (track.id & 0xFF0000) >> 16,
11248    (track.id & 0xFF00) >> 8,
11249    (track.id & 0xFF), // track_ID
11250    0x00, 0x00, 0x00, 0x01, // default_sample_description_index
11251    0x00, 0x00, 0x00, 0x00, // default_sample_duration
11252    0x00, 0x00, 0x00, 0x00, // default_sample_size
11253    0x00, 0x01, 0x00, 0x01 // default_sample_flags
11254  ]);
11255  // the last two bytes of default_sample_flags is the sample
11256  // degradation priority, a hint about the importance of this sample
11257  // relative to others. Lower the degradation priority for all sample
11258  // types other than video.
11259  if (track.type !== 'video') {
11260    result[result.length - 1] = 0x00;
11261  }
11262
11263  return box(types.trex, result);
11264};
11265
11266(function() {
11267  var audioTrun, videoTrun, trunHeader;
11268
11269  // This method assumes all samples are uniform. That is, if a
11270  // duration is present for the first sample, it will be present for
11271  // all subsequent samples.
11272  // see ISO/IEC 14496-12:2012, Section 8.8.8.1
11273  trunHeader = function(samples, offset) {
11274    var durationPresent = 0, sizePresent = 0,
11275        flagsPresent = 0, compositionTimeOffset = 0;
11276
11277    // trun flag constants
11278    if (samples.length) {
11279      if (samples[0].duration !== undefined) {
11280        durationPresent = 0x1;
11281      }
11282      if (samples[0].size !== undefined) {
11283        sizePresent = 0x2;
11284      }
11285      if (samples[0].flags !== undefined) {
11286        flagsPresent = 0x4;
11287      }
11288      if (samples[0].compositionTimeOffset !== undefined) {
11289        compositionTimeOffset = 0x8;
11290      }
11291    }
11292
11293    return [
11294      0x00, // version 0
11295      0x00,
11296      durationPresent | sizePresent | flagsPresent | compositionTimeOffset,
11297      0x01, // flags
11298      (samples.length & 0xFF000000) >>> 24,
11299      (samples.length & 0xFF0000) >>> 16,
11300      (samples.length & 0xFF00) >>> 8,
11301      samples.length & 0xFF, // sample_count
11302      (offset & 0xFF000000) >>> 24,
11303      (offset & 0xFF0000) >>> 16,
11304      (offset & 0xFF00) >>> 8,
11305      offset & 0xFF // data_offset
11306    ];
11307  };
11308
11309  videoTrun = function(track, offset) {
11310    var bytes, samples, sample, i;
11311
11312    samples = track.samples || [];
11313    offset += 8 + 12 + (16 * samples.length);
11314
11315    bytes = trunHeader(samples, offset);
11316
11317    for (i = 0; i < samples.length; i++) {
11318      sample = samples[i];
11319      bytes = bytes.concat([
11320        (sample.duration & 0xFF000000) >>> 24,
11321        (sample.duration & 0xFF0000) >>> 16,
11322        (sample.duration & 0xFF00) >>> 8,
11323        sample.duration & 0xFF, // sample_duration
11324        (sample.size & 0xFF000000) >>> 24,
11325        (sample.size & 0xFF0000) >>> 16,
11326        (sample.size & 0xFF00) >>> 8,
11327        sample.size & 0xFF, // sample_size
11328        (sample.flags.isLeading << 2) | sample.flags.dependsOn,
11329        (sample.flags.isDependedOn << 6) |
11330          (sample.flags.hasRedundancy << 4) |
11331          (sample.flags.paddingValue << 1) |
11332          sample.flags.isNonSyncSample,
11333        sample.flags.degradationPriority & 0xF0 << 8,
11334        sample.flags.degradationPriority & 0x0F, // sample_flags
11335        (sample.compositionTimeOffset & 0xFF000000) >>> 24,
11336        (sample.compositionTimeOffset & 0xFF0000) >>> 16,
11337        (sample.compositionTimeOffset & 0xFF00) >>> 8,
11338        sample.compositionTimeOffset & 0xFF // sample_composition_time_offset
11339      ]);
11340    }
11341    return box(types.trun, new Uint8Array(bytes));
11342  };
11343
11344  audioTrun = function(track, offset) {
11345    var bytes, samples, sample, i;
11346
11347    samples = track.samples || [];
11348    offset += 8 + 12 + (8 * samples.length);
11349
11350    bytes = trunHeader(samples, offset);
11351
11352    for (i = 0; i < samples.length; i++) {
11353      sample = samples[i];
11354      bytes = bytes.concat([
11355        (sample.duration & 0xFF000000) >>> 24,
11356        (sample.duration & 0xFF0000) >>> 16,
11357        (sample.duration & 0xFF00) >>> 8,
11358        sample.duration & 0xFF, // sample_duration
11359        (sample.size & 0xFF000000) >>> 24,
11360        (sample.size & 0xFF0000) >>> 16,
11361        (sample.size & 0xFF00) >>> 8,
11362        sample.size & 0xFF]); // sample_size
11363    }
11364
11365    return box(types.trun, new Uint8Array(bytes));
11366  };
11367
11368  trun = function(track, offset) {
11369    if (track.type === 'audio') {
11370      return audioTrun(track, offset);
11371    }
11372
11373    return videoTrun(track, offset);
11374  };
11375}());
11376
11377module.exports = {
11378  ftyp: ftyp,
11379  mdat: mdat,
11380  moof: moof,
11381  moov: moov,
11382  initSegment: function(tracks) {
11383    var
11384      fileType = ftyp(),
11385      movie = moov(tracks),
11386      result;
11387
11388    result = new Uint8Array(fileType.byteLength + movie.byteLength);
11389    result.set(fileType);
11390    result.set(movie, fileType.byteLength);
11391    return result;
11392  }
11393};
11394
11395},{}],
1139580:[function(require,module,exports){
11396/**
11397 * mux.js
11398 *
11399 * Copyright (c) 2015 Brightcove
11400 * All rights reserved.
11401 *
11402 * Utilities to detect basic properties and metadata about MP4s.
11403 */
11404'use strict';
11405
11406var findBox, parseType, timescale, startTime;
11407
11408// Find the data for a box specified by its path
11409findBox = function(data, path) {
11410  var results = [],
11411      i, size, type, end, subresults;
11412
11413  if (!path.length) {
11414    // short-circuit the search for empty paths
11415    return null;
11416  }
11417
11418  for (i = 0; i < data.byteLength;) {
11419    size  = data[i]     << 24;
11420    size |= data[i + 1] << 16;
11421    size |= data[i + 2] << 8;
11422    size |= data[i + 3];
11423
11424    type = parseType(data.subarray(i + 4, i + 8));
11425
11426    end = size > 1 ? i + size : data.byteLength;
11427
11428    if (type === path[0]) {
11429      if (path.length === 1) {
11430        // this is the end of the path and we've found the box we were
11431        // looking for
11432        results.push(data.subarray(i + 8, end));
11433      } else {
11434        // recursively search for the next box along the path
11435        subresults = findBox(data.subarray(i + 8, end), path.slice(1));
11436        if (subresults.length) {
11437          results = results.concat(subresults);
11438        }
11439      }
11440    }
11441    i = end;
11442  }
11443
11444  // we've finished searching all of data
11445  return results;
11446};
11447
11448/**
11449 * Returns the string representation of an ASCII encoded four byte buffer.
11450 * @param buffer {Uint8Array} a four-byte buffer to translate
11451 * @return {string} the corresponding string
11452 */
11453parseType = function(buffer) {
11454  var result = '';
11455  result += String.fromCharCode(buffer[0]);
11456  result += String.fromCharCode(buffer[1]);
11457  result += String.fromCharCode(buffer[2]);
11458  result += String.fromCharCode(buffer[3]);
11459  return result;
11460};
11461
11462/**
11463 * Parses an MP4 initialization segment and extracts the timescale
11464 * values for any declared tracks. Timescale values indicate the
11465 * number of clock ticks per second to assume for time-based values
11466 * elsewhere in the MP4.
11467 *
11468 * To determine the start time of an MP4, you need two pieces of
11469 * information: the timescale unit and the earliest base media decode
11470 * time. Multiple timescales can be specified within an MP4 but the
11471 * base media decode time is always expressed in the timescale from
11472 * the media header box for the track:
11473 * ```
11474 * moov > trak > mdia > mdhd.timescale
11475 * ```
11476 * @param init {Uint8Array} the bytes of the init segment
11477 * @return {object} a hash of track ids to timescale values or null if
11478 * the init segment is malformed.
11479 */
11480timescale = function(init) {
11481  var
11482    result = {},
11483    traks = findBox(init, ['moov', 'trak']);
11484
11485  // mdhd timescale
11486  return traks.reduce(function(result, trak) {
11487    var tkhd, version, index, id, mdhd;
11488
11489    tkhd = findBox(trak, ['tkhd'])[0];
11490    if (!tkhd) {
11491      return null;
11492    }
11493    version = tkhd[0];
11494    index = version === 0 ? 12 : 20;
11495    id = tkhd[index]     << 24 |
11496         tkhd[index + 1] << 16 |
11497         tkhd[index + 2] <<  8 |
11498         tkhd[index + 3];
11499
11500    mdhd = findBox(trak, ['mdia', 'mdhd'])[0];
11501    if (!mdhd) {
11502      return null;
11503    }
11504    version = mdhd[0];
11505    index = version === 0 ? 12 : 20;
11506    result[id] = mdhd[index]     << 24 |
11507                 mdhd[index + 1] << 16 |
11508                 mdhd[index + 2] <<  8 |
11509                 mdhd[index + 3];
11510    return result;
11511  }, result);
11512};
11513
11514/**
11515 * Determine the base media decode start time, in seconds, for an MP4
11516 * fragment. If multiple fragments are specified, the earliest time is
11517 * returned.
11518 *
11519 * The base media decode time can be parsed from track fragment
11520 * metadata:
11521 * ```
11522 * moof > traf > tfdt.baseMediaDecodeTime
11523 * ```
11524 * It requires the timescale value from the mdhd to interpret.
11525 *
11526 * @param timescale {object} a hash of track ids to timescale values.
11527 * @return {number} the earliest base media decode start time for the
11528 * fragment, in seconds
11529 */
11530startTime = function(timescale, fragment) {
11531  var trafs, baseTimes, result;
11532
11533  // we need info from two childrend of each track fragment box
11534  trafs = findBox(fragment, ['moof', 'traf']);
11535
11536  // determine the start times for each track
11537  baseTimes = [].concat.apply([], trafs.map(function(traf) {
11538    return findBox(traf, ['tfhd']).map(function(tfhd) {
11539      var id, scale, baseTime;
11540
11541      // get the track id from the tfhd
11542      id = tfhd[4] << 24 |
11543           tfhd[5] << 16 |
11544           tfhd[6] << 8 |
11545           tfhd[7];
11546      // assume a 90kHz clock if no timescale was specified
11547      scale = timescale[id] || 90e3;
11548
11549      // get the base media decode time from the tfdt
11550      baseTime = findBox(traf, ['tfdt']).map(function(tfdt) {
11551        var version, result;
11552
11553        version = tfdt[0];
11554        result = tfdt[4] << 24 |
11555                 tfdt[5] << 16 |
11556                 tfdt[6] <<  8 |
11557                 tfdt[7];
11558        if (version ===  1) {
11559          result *= Math.pow(2, 32);
11560          result += tfdt[8]  << 24 |
11561                    tfdt[9]  << 16 |
11562                    tfdt[10] <<  8 |
11563                    tfdt[11];
11564        }
11565        return result;
11566      })[0];
11567      baseTime = baseTime || Infinity;
11568
11569      // convert base time to seconds
11570      return baseTime / scale;
11571    });
11572  }));
11573
11574  // return the minimum
11575  result = Math.min.apply(null, baseTimes);
11576  return isFinite(result) ? result : 0;
11577};
11578
11579module.exports = {
11580  parseType: parseType,
11581  timescale: timescale,
11582  startTime: startTime
11583};
11584
11585},{}],81:[function(require,module,exports){
11586/**
11587 * mux.js
11588 *
11589 * Copyright (c) 2015 Brightcove
11590 * All rights reserved.
11591 *
11592 * A stream-based mp2t to mp4 converter. This utility can be used to
11593 * deliver mp4s to a SourceBuffer on platforms that support native
11594 * Media Source Extensions.
11595 */
11596'use strict';
11597
11598var Stream = require('../utils/stream.js');
11599var mp4 = require('./mp4-generator.js');
11600var m2ts = require('../m2ts/m2ts.js');
11601var AdtsStream = require('../codecs/adts.js');
11602var H264Stream = require('../codecs/h264').H264Stream;
11603var AacStream = require('../aac');
11604
11605// constants
11606var AUDIO_PROPERTIES = [
11607  'audioobjecttype',
11608  'channelcount',
11609  'samplerate',
11610  'samplingfrequencyindex',
11611  'samplesize'
11612];
11613
11614var VIDEO_PROPERTIES = [
11615  'width',
11616  'height',
11617  'profileIdc',
11618  'levelIdc',
11619  'profileCompatibility'
11620];
11621
11622// object types
11623var VideoSegmentStream, AudioSegmentStream, Transmuxer, CoalesceStream;
11624
11625// Helper functions
11626var
11627  createDefaultSample,
11628  isLikelyAacData,
11629  collectDtsInfo,
11630  clearDtsInfo,
11631  calculateTrackBaseMediaDecodeTime,
11632  arrayEquals,
11633  sumFrameByteLengths;
11634
11635/**
11636 * Default sample object
11637 * see ISO/IEC 14496-12:2012, section 8.6.4.3
11638 */
11639createDefaultSample = function() {
11640  return {
11641    size: 0,
11642    flags: {
11643      isLeading: 0,
11644      dependsOn: 1,
11645      isDependedOn: 0,
11646      hasRedundancy: 0,
11647      degradationPriority: 0
11648    }
11649  };
11650};
11651
11652isLikelyAacData = function(data) {
11653  if ((data[0] === 'I'.charCodeAt(0)) &&
11654      (data[1] === 'D'.charCodeAt(0)) &&
11655      (data[2] === '3'.charCodeAt(0))) {
11656    return true;
11657  }
11658  return false;
vendor: 38,330 bytes, lines 11659-12888
11659};
11660
11661/**
11662 * Compare two arrays (even typed) for same-ness
11663 */
11664arrayEquals = function(a, b) {
11665  var
11666    i;
11667
11668  if (a.length !== b.length) {
11669    return false;
11670  }
11671
11672  // compare the value of each element in the array
11673  for (i = 0; i < a.length; i++) {
11674    if (a[i] !== b[i]) {
11675      return false;
11676    }
11677  }
11678
11679  return true;
11680};
11681
11682/**
11683 * Sum the `byteLength` properties of the data in each AAC frame
11684 */
11685sumFrameByteLengths = function(array) {
11686  var
11687    i,
11688    currentObj,
11689    sum = 0;
11690
11691  // sum the byteLength's all each nal unit in the frame
11692  for (i = 0; i < array.length; i++) {
11693    currentObj = array[i];
11694    sum += currentObj.data.byteLength;
11695  }
11696
11697  return sum;
11698};
11699
11700/**
11701 * Constructs a single-track, ISO BMFF media segment from AAC data
11702 * events. The output of this stream can be fed to a SourceBuffer
11703 * configured with a suitable initialization segment.
11704 */
11705AudioSegmentStream = function(track) {
11706  var
11707    adtsFrames = [],
11708    sequenceNumber = 0,
11709    earliestAllowedDts = 0;
11710
11711  AudioSegmentStream.prototype.init.call(this);
11712
11713  this.push = function(data) {
11714    collectDtsInfo(track, data);
11715
11716    if (track) {
11717      AUDIO_PROPERTIES.forEach(function(prop) {
11718        track[prop] = data[prop];
11719      });
11720    }
11721
11722    // buffer audio data until end() is called
11723    adtsFrames.push(data);
11724  };
11725
11726  this.setEarliestDts = function(earliestDts) {
11727    earliestAllowedDts = earliestDts - track.timelineStartInfo.baseMediaDecodeTime;
11728  };
11729
11730  this.flush = function() {
11731    var
11732      frames,
11733      moof,
11734      mdat,
11735      boxes;
11736
11737    // return early if no audio data has been observed
11738    if (adtsFrames.length === 0) {
11739      this.trigger('done', 'AudioSegmentStream');
11740      return;
11741    }
11742
11743    frames = this.trimAdtsFramesByEarliestDts_(adtsFrames);
11744
11745    // we have to build the index from byte locations to
11746    // samples (that is, adts frames) in the audio data
11747    track.samples = this.generateSampleTable_(frames);
11748
11749    // concatenate the audio data to constuct the mdat
11750    mdat = mp4.mdat(this.concatenateFrameData_(frames));
11751
11752    adtsFrames = [];
11753
11754    calculateTrackBaseMediaDecodeTime(track);
11755    moof = mp4.moof(sequenceNumber, [track]);
11756    boxes = new Uint8Array(moof.byteLength + mdat.byteLength);
11757
11758    // bump the sequence number for next time
11759    sequenceNumber++;
11760
11761    boxes.set(moof);
11762    boxes.set(mdat, moof.byteLength);
11763
11764    clearDtsInfo(track);
11765
11766    this.trigger('data', {track: track, boxes: boxes});
11767    this.trigger('done', 'AudioSegmentStream');
11768  };
11769
11770  // If the audio segment extends before the earliest allowed dts
11771  // value, remove AAC frames until starts at or after the earliest
11772  // allowed DTS so that we don't end up with a negative baseMedia-
11773  // DecodeTime for the audio track
11774  this.trimAdtsFramesByEarliestDts_ = function(adtsFrames) {
11775    if (track.minSegmentDts >= earliestAllowedDts) {
11776      return adtsFrames;
11777    }
11778
11779    // We will need to recalculate the earliest segment Dts
11780    track.minSegmentDts = Infinity;
11781
11782    return adtsFrames.filter(function(currentFrame) {
11783      // If this is an allowed frame, keep it and record it's Dts
11784      if (currentFrame.dts >= earliestAllowedDts) {
11785        track.minSegmentDts = Math.min(track.minSegmentDts, currentFrame.dts);
11786        track.minSegmentPts = track.minSegmentDts;
11787        return true;
11788      }
11789      // Otherwise, discard it
11790      return false;
11791    });
11792  };
11793
11794  // generate the track's raw mdat data from an array of frames
11795  this.generateSampleTable_ = function(frames) {
11796    var
11797      i,
11798      currentFrame,
11799      samples = [];
11800
11801    for (i = 0; i < frames.length; i++) {
11802      currentFrame = frames[i];
11803      samples.push({
11804        size: currentFrame.data.byteLength,
11805        duration: 1024 // For AAC audio, all samples contain 1024 samples
11806      });
11807    }
11808    return samples;
11809  };
11810
11811  // generate the track's sample table from an array of frames
11812  this.concatenateFrameData_ = function(frames) {
11813    var
11814      i,
11815      currentFrame,
11816      dataOffset = 0,
11817      data = new Uint8Array(sumFrameByteLengths(frames));
11818
11819    for (i = 0; i < frames.length; i++) {
11820      currentFrame = frames[i];
11821
11822      data.set(currentFrame.data, dataOffset);
11823      dataOffset += currentFrame.data.byteLength;
11824    }
11825    return data;
11826  };
11827};
11828
11829AudioSegmentStream.prototype = new Stream();
11830
11831/**
11832 * Constructs a single-track, ISO BMFF media segment from H264 data
11833 * events. The output of this stream can be fed to a SourceBuffer
11834 * configured with a suitable initialization segment.
11835 * @param track {object} track metadata configuration
11836 */
11837VideoSegmentStream = function(track) {
11838  var
11839    sequenceNumber = 0,
11840    nalUnits = [],
11841    config,
11842    pps;
11843
11844  VideoSegmentStream.prototype.init.call(this);
11845
11846  delete track.minPTS;
11847
11848  this.gopCache_ = [];
11849
11850  this.push = function(nalUnit) {
11851    collectDtsInfo(track, nalUnit);
11852
11853    // record the track config
11854    if (nalUnit.nalUnitType === 'seq_parameter_set_rbsp' && !config) {
11855      config = nalUnit.config;
11856      track.sps = [nalUnit.data];
11857
11858      VIDEO_PROPERTIES.forEach(function(prop) {
11859        track[prop] = config[prop];
11860      }, this);
11861    }
11862
11863    if (nalUnit.nalUnitType === 'pic_parameter_set_rbsp' &&
11864        !pps) {
11865      pps = nalUnit.data;
11866      track.pps = [nalUnit.data];
11867    }
11868
11869    // buffer video until flush() is called
11870    nalUnits.push(nalUnit);
11871  };
11872
11873  this.flush = function() {
11874    var
11875      frames,
11876      gopForFusion,
11877      gops,
11878      moof,
11879      mdat,
11880      boxes;
11881
11882    // Throw away nalUnits at the start of the byte stream until
11883    // we find the first AUD
11884    while (nalUnits.length) {
11885      if (nalUnits[0].nalUnitType === 'access_unit_delimiter_rbsp') {
11886        break;
11887      }
11888      nalUnits.shift();
11889    }
11890
11891    // Return early if no video data has been observed
11892    if (nalUnits.length === 0) {
11893      this.resetStream_();
11894      this.trigger('done', 'VideoSegmentStream');
11895      return;
11896    }
11897
11898    // Organize the raw nal-units into arrays that represent
11899    // higher-level constructs such as frames and gops
11900    // (group-of-pictures)
11901    frames = this.groupNalsIntoFrames_(nalUnits);
11902    gops = this.groupFramesIntoGops_(frames);
11903
11904    // If the first frame of this fragment is not a keyframe we have
11905    // a problem since MSE (on Chrome) requires a leading keyframe.
11906    //
11907    // We have two approaches to repairing this situation:
11908    // 1) GOP-FUSION:
11909    //    This is where we keep track of the GOPS (group-of-pictures)
11910    //    from previous fragments and attempt to find one that we can
11911    //    prepend to the current fragment in order to create a valid
11912    //    fragment.
11913    // 2) KEYFRAME-PULLING:
11914    //    Here we search for the first keyframe in the fragment and
11915    //    throw away all the frames between the start of the fragment
11916    //    and that keyframe. We then extend the duration and pull the
11917    //    PTS of the keyframe forward so that it covers the time range
11918    //    of the frames that were disposed of.
11919    //
11920    // #1 is far prefereable over #2 which can cause "stuttering" but
11921    // requires more things to be just right.
11922    if (!gops[0][0].keyFrame) {
11923      // Search for a gop for fusion from our gopCache
11924      gopForFusion = this.getGopForFusion_(nalUnits[0], track);
11925
11926      if (gopForFusion) {
11927        gops.unshift(gopForFusion);
11928        // Adjust Gops' metadata to account for the inclusion of the
11929        // new gop at the beginning
11930        gops.byteLength += gopForFusion.byteLength;
11931        gops.nalCount += gopForFusion.nalCount;
11932        gops.pts = gopForFusion.pts;
11933        gops.dts = gopForFusion.dts;
11934        gops.duration += gopForFusion.duration;
11935      } else {
11936        // If we didn't find a candidate gop fall back to keyrame-pulling
11937        gops = this.extendFirstKeyFrame_(gops);
11938      }
11939    }
11940    collectDtsInfo(track, gops);
11941
11942    // First, we have to build the index from byte locations to
11943    // samples (that is, frames) in the video data
11944    track.samples = this.generateSampleTable_(gops);
11945
11946    // Concatenate the video data and construct the mdat
11947    mdat = mp4.mdat(this.concatenateNalData_(gops));
11948
11949    // save all the nals in the last GOP into the gop cache
11950    this.gopCache_.unshift({
11951      gop: gops.pop(),
11952      pps: track.pps,
11953      sps: track.sps
11954    });
11955
11956    // Keep a maximum of 6 GOPs in the cache
11957    this.gopCache_.length = Math.min(6, this.gopCache_.length);
11958
11959    // Clear nalUnits
11960    nalUnits = [];
11961
11962    calculateTrackBaseMediaDecodeTime(track);
11963
11964    this.trigger('timelineStartInfo', track.timelineStartInfo);
11965
11966    moof = mp4.moof(sequenceNumber, [track]);
11967
11968    // it would be great to allocate this array up front instead of
11969    // throwing away hundreds of media segment fragments
11970    boxes = new Uint8Array(moof.byteLength + mdat.byteLength);
11971
11972    // Bump the sequence number for next time
11973    sequenceNumber++;
11974
11975    boxes.set(moof);
11976    boxes.set(mdat, moof.byteLength);
11977
11978    this.trigger('data', {track: track, boxes: boxes});
11979
11980    this.resetStream_();
11981
11982    // Continue with the flush process now
11983    this.trigger('done', 'VideoSegmentStream');
11984  };
11985
11986  this.resetStream_ = function() {
11987    clearDtsInfo(track);
11988
11989    // reset config and pps because they may differ across segments
11990    // for instance, when we are rendition switching
11991    config = undefined;
11992    pps = undefined;
11993  };
11994
11995  // Search for a candidate Gop for gop-fusion from the gop cache and
11996  // return it or return null if no good candidate was found
11997  this.getGopForFusion_ = function(nalUnit) {
11998    var
11999      halfSecond = 45000, // Half-a-second in a 90khz clock
12000      allowableOverlap = 10000, // About 3 frames @ 30fps
12001      nearestDistance = Infinity,
12002      dtsDistance,
12003      nearestGopObj,
12004      currentGop,
12005      currentGopObj,
12006      i;
12007
12008    // Search for the GOP nearest to the beginning of this nal unit
12009    for (i = 0; i < this.gopCache_.length; i++) {
12010      currentGopObj = this.gopCache_[i];
12011      currentGop = currentGopObj.gop;
12012
12013      // Reject Gops with different SPS or PPS
12014      if (!(track.pps && arrayEquals(track.pps[0], currentGopObj.pps[0])) ||
12015          !(track.sps && arrayEquals(track.sps[0], currentGopObj.sps[0]))) {
12016        continue;
12017      }
12018
12019      // Reject Gops that would require a negative baseMediaDecodeTime
12020      if (currentGop.dts < track.timelineStartInfo.dts) {
12021        continue;
12022      }
12023
12024      // The distance between the end of the gop and the start of the nalUnit
12025      dtsDistance = (nalUnit.dts - currentGop.dts) - currentGop.duration;
12026
12027      // Only consider GOPS that start before the nal unit and end within
12028      // a half-second of the nal unit
12029      if (dtsDistance >= -allowableOverlap &&
12030          dtsDistance <= halfSecond) {
12031
12032        // Always use the closest GOP we found if there is more than
12033        // one candidate
12034        if (!nearestGopObj ||
12035            nearestDistance > dtsDistance) {
12036          nearestGopObj = currentGopObj;
12037          nearestDistance = dtsDistance;
12038        }
12039      }
12040    }
12041
12042    if (nearestGopObj) {
12043      return nearestGopObj.gop;
12044    }
12045    return null;
12046  };
12047
12048  this.extendFirstKeyFrame_ = function(gops) {
12049    var currentGop;
12050
12051    if (!gops[0][0].keyFrame) {
12052      // Remove the first GOP
12053      currentGop = gops.shift();
12054
12055      gops.byteLength -=  currentGop.byteLength;
12056      gops.nalCount -= currentGop.nalCount;
12057
12058      // Extend the first frame of what is now the
12059      // first gop to cover the time period of the
12060      // frames we just removed
12061      gops[0][0].dts = currentGop.dts;
12062      gops[0][0].pts = currentGop.pts;
12063      gops[0][0].duration += currentGop.duration;
12064    }
12065
12066    return gops;
12067  };
12068
12069  // Convert an array of nal units into an array of frames with each frame being
12070  // composed of the nal units that make up that frame
12071  // Also keep track of cummulative data about the frame from the nal units such
12072  // as the frame duration, starting pts, etc.
12073  this.groupNalsIntoFrames_ = function(nalUnits) {
12074    var
12075      i,
12076      currentNal,
12077      currentFrame = [],
12078      frames = [];
12079
12080    currentFrame.byteLength = 0;
12081
12082    for (i = 0; i < nalUnits.length; i++) {
12083      currentNal = nalUnits[i];
12084
12085      // Split on 'aud'-type nal units
12086      if (currentNal.nalUnitType === 'access_unit_delimiter_rbsp') {
12087        // Since the very first nal unit is expected to be an AUD
12088        // only push to the frames array when currentFrame is not empty
12089        if (currentFrame.length) {
12090          currentFrame.duration = currentNal.dts - currentFrame.dts;
12091          frames.push(currentFrame);
12092        }
12093        currentFrame = [currentNal];
12094        currentFrame.byteLength = currentNal.data.byteLength;
12095        currentFrame.pts = currentNal.pts;
12096        currentFrame.dts = currentNal.dts;
12097      } else {
12098        // Specifically flag key frames for ease of use later
12099        if (currentNal.nalUnitType === 'slice_layer_without_partitioning_rbsp_idr') {
12100          currentFrame.keyFrame = true;
12101        }
12102        currentFrame.duration = currentNal.dts - currentFrame.dts;
12103        currentFrame.byteLength += currentNal.data.byteLength;
12104        currentFrame.push(currentNal);
12105      }
12106    }
12107
12108    // For the last frame, use the duration of the previous frame if we
12109    // have nothing better to go on
12110    if (frames.length &&
12111        (!currentFrame.duration ||
12112         currentFrame.duration <= 0)) {
12113      currentFrame.duration = frames[frames.length - 1].duration;
12114    }
12115
12116    // Push the final frame
12117    frames.push(currentFrame);
12118    return frames;
12119  };
12120
12121  // Convert an array of frames into an array of Gop with each Gop being composed
12122  // of the frames that make up that Gop
12123  // Also keep track of cummulative data about the Gop from the frames such as the
12124  // Gop duration, starting pts, etc.
12125  this.groupFramesIntoGops_ = function(frames) {
12126    var
12127      i,
12128      currentFrame,
12129      currentGop = [],
12130      gops = [];
12131
12132    // We must pre-set some of the values on the Gop since we
12133    // keep running totals of these values
12134    currentGop.byteLength = 0;
12135    currentGop.nalCount = 0;
12136    currentGop.duration = 0;
12137    currentGop.pts = frames[0].pts;
12138    currentGop.dts = frames[0].dts;
12139
12140    // store some metadata about all the Gops
12141    gops.byteLength = 0;
12142    gops.nalCount = 0;
12143    gops.duration = 0;
12144    gops.pts = frames[0].pts;
12145    gops.dts = frames[0].dts;
12146
12147    for (i = 0; i < frames.length; i++) {
12148      currentFrame = frames[i];
12149
12150      if (currentFrame.keyFrame) {
12151        // Since the very first frame is expected to be an keyframe
12152        // only push to the gops array when currentGop is not empty
12153        if (currentGop.length) {
12154          gops.push(currentGop);
12155          gops.byteLength += currentGop.byteLength;
12156          gops.nalCount += currentGop.nalCount;
12157          gops.duration += currentGop.duration;
12158        }
12159
12160        currentGop = [currentFrame];
12161        currentGop.nalCount = currentFrame.length;
12162        currentGop.byteLength = currentFrame.byteLength;
12163        currentGop.pts = currentFrame.pts;
12164        currentGop.dts = currentFrame.dts;
12165        currentGop.duration = currentFrame.duration;
12166      } else {
12167        currentGop.duration += currentFrame.duration;
12168        currentGop.nalCount += currentFrame.length;
12169        currentGop.byteLength += currentFrame.byteLength;
12170        currentGop.push(currentFrame);
12171      }
12172    }
12173
12174    if (gops.length && currentGop.duration <= 0) {
12175      currentGop.duration = gops[gops.length - 1].duration;
12176    }
12177    gops.byteLength += currentGop.byteLength;
12178    gops.nalCount += currentGop.nalCount;
12179    gops.duration += currentGop.duration;
12180
12181    // push the final Gop
12182    gops.push(currentGop);
12183    return gops;
12184  };
12185
12186  // generate the track's sample table from an array of gops
12187  this.generateSampleTable_ = function(gops, baseDataOffset) {
12188    var
12189      h, i,
12190      sample,
12191      currentGop,
12192      currentFrame,
12193      dataOffset = baseDataOffset || 0,
12194      samples = [];
12195
12196    for (h = 0; h < gops.length; h++) {
12197      currentGop = gops[h];
12198
12199      for (i = 0; i < currentGop.length; i++) {
12200        currentFrame = currentGop[i];
12201
12202        sample = createDefaultSample();
12203
12204        sample.dataOffset = dataOffset;
12205        sample.compositionTimeOffset = currentFrame.pts - currentFrame.dts;
12206        sample.duration = currentFrame.duration;
12207        sample.size = 4 * currentFrame.length; // Space for nal unit size
12208        sample.size += currentFrame.byteLength;
12209
12210        if (currentFrame.keyFrame) {
12211          sample.flags.dependsOn = 2;
12212        }
12213
12214        dataOffset += sample.size;
12215
12216        samples.push(sample);
12217      }
12218    }
12219    return samples;
12220  };
12221
12222  // generate the track's raw mdat data from an array of gops
12223  this.concatenateNalData_ = function(gops) {
12224    var
12225      h, i, j,
12226      currentGop,
12227      currentFrame,
12228      currentNal,
12229      dataOffset = 0,
12230      nalsByteLength = gops.byteLength,
12231      numberOfNals = gops.nalCount,
12232      totalByteLength = nalsByteLength + 4 * numberOfNals,
12233      data = new Uint8Array(totalByteLength),
12234      view = new DataView(data.buffer);
12235
12236    // For each Gop..
12237    for (h = 0; h < gops.length; h++) {
12238      currentGop = gops[h];
12239
12240      // For each Frame..
12241      for (i = 0; i < currentGop.length; i++) {
12242        currentFrame = currentGop[i];
12243
12244        // For each NAL..
12245        for (j = 0; j < currentFrame.length; j++) {
12246          currentNal = currentFrame[j];
12247
12248          view.setUint32(dataOffset, currentNal.data.byteLength);
12249          dataOffset += 4;
12250          data.set(currentNal.data, dataOffset);
12251          dataOffset += currentNal.data.byteLength;
12252        }
12253      }
12254    }
12255    return data;
12256  };
12257};
12258
12259VideoSegmentStream.prototype = new Stream();
12260
12261/**
12262 * Store information about the start and end of the track and the
12263 * duration for each frame/sample we process in order to calculate
12264 * the baseMediaDecodeTime
12265 */
12266collectDtsInfo = function(track, data) {
12267  if (typeof data.pts === 'number') {
12268    if (track.timelineStartInfo.pts === undefined) {
12269      track.timelineStartInfo.pts = data.pts;
12270    }
12271
12272    if (track.minSegmentPts === undefined) {
12273      track.minSegmentPts = data.pts;
12274    } else {
12275      track.minSegmentPts = Math.min(track.minSegmentPts, data.pts);
12276    }
12277
12278    if (track.maxSegmentPts === undefined) {
12279      track.maxSegmentPts = data.pts;
12280    } else {
12281      track.maxSegmentPts = Math.max(track.maxSegmentPts, data.pts);
12282    }
12283  }
12284
12285  if (typeof data.dts === 'number') {
12286    if (track.timelineStartInfo.dts === undefined) {
12287      track.timelineStartInfo.dts = data.dts;
12288    }
12289
12290    if (track.minSegmentDts === undefined) {
12291      track.minSegmentDts = data.dts;
12292    } else {
12293      track.minSegmentDts = Math.min(track.minSegmentDts, data.dts);
12294    }
12295
12296    if (track.maxSegmentDts === undefined) {
12297      track.maxSegmentDts = data.dts;
12298    } else {
12299      track.maxSegmentDts = Math.max(track.maxSegmentDts, data.dts);
12300    }
12301  }
12302};
12303
12304/**
12305 * Clear values used to calculate the baseMediaDecodeTime between
12306 * tracks
12307 */
12308clearDtsInfo = function(track) {
12309  delete track.minSegmentDts;
12310  delete track.maxSegmentDts;
12311  delete track.minSegmentPts;
12312  delete track.maxSegmentPts;
12313};
12314
12315/**
12316 * Calculate the track's baseMediaDecodeTime based on the earliest
12317 * DTS the transmuxer has ever seen and the minimum DTS for the
12318 * current track
12319 */
12320calculateTrackBaseMediaDecodeTime = function(track) {
12321  var
12322    oneSecondInPTS = 90000, // 90kHz clock
12323    scale,
12324    // Calculate the distance, in time, that this segment starts from the start
12325    // of the timeline (earliest time seen since the transmuxer initialized)
12326    timeSinceStartOfTimeline = track.minSegmentDts - track.timelineStartInfo.dts,
12327    // Calculate the first sample's effective compositionTimeOffset
12328    firstSampleCompositionOffset = track.minSegmentPts - track.minSegmentDts;
12329
12330  // track.timelineStartInfo.baseMediaDecodeTime is the location, in time, where
12331  // we want the start of the first segment to be placed
12332  track.baseMediaDecodeTime = track.timelineStartInfo.baseMediaDecodeTime;
12333
12334  // Add to that the distance this segment is from the very first
12335  track.baseMediaDecodeTime += timeSinceStartOfTimeline;
12336
12337  // Subtract this segment's "compositionTimeOffset" so that the first frame of
12338  // this segment is displayed exactly at the `baseMediaDecodeTime` or at the
12339  // end of the previous segment
12340  track.baseMediaDecodeTime -= firstSampleCompositionOffset;
12341
12342  // baseMediaDecodeTime must not become negative
12343  track.baseMediaDecodeTime = Math.max(0, track.baseMediaDecodeTime);
12344
12345  if (track.type === 'audio') {
12346    // Audio has a different clock equal to the sampling_rate so we need to
12347    // scale the PTS values into the clock rate of the track
12348    scale = track.samplerate / oneSecondInPTS;
12349    track.baseMediaDecodeTime *= scale;
12350    track.baseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime);
12351  }
12352};
12353
12354/**
12355 * A Stream that can combine multiple streams (ie. audio & video)
12356 * into a single output segment for MSE. Also supports audio-only
12357 * and video-only streams.
12358 */
12359CoalesceStream = function(options, metadataStream) {
12360  // Number of Tracks per output segment
12361  // If greater than 1, we combine multiple
12362  // tracks into a single segment
12363  this.numberOfTracks = 0;
12364  this.metadataStream = metadataStream;
12365
12366  if (typeof options.remux !== 'undefined') {
12367    this.remuxTracks = !!options.remux;
12368  } else {
12369    this.remuxTracks = true;
12370  }
12371
12372  this.pendingTracks = [];
12373  this.videoTrack = null;
12374  this.pendingBoxes = [];
12375  this.pendingCaptions = [];
12376  this.pendingMetadata = [];
12377  this.pendingBytes = 0;
12378  this.emittedTracks = 0;
12379
12380  CoalesceStream.prototype.init.call(this);
12381
12382  // Take output from multiple
12383  this.push = function(output) {
12384    // buffer incoming captions until the associated video segment
12385    // finishes
12386    if (output.text) {
12387      return this.pendingCaptions.push(output);
12388    }
12389    // buffer incoming id3 tags until the final flush
12390    if (output.frames) {
12391      return this.pendingMetadata.push(output);
12392    }
12393
12394    // Add this track to the list of pending tracks and store
12395    // important information required for the construction of
12396    // the final segment
12397    this.pendingTracks.push(output.track);
12398    this.pendingBoxes.push(output.boxes);
12399    this.pendingBytes += output.boxes.byteLength;
12400
12401    if (output.track.type === 'video') {
12402      this.videoTrack = output.track;
12403    }
12404    if (output.track.type === 'audio') {
12405      this.audioTrack = output.track;
12406    }
12407  };
12408};
12409
12410CoalesceStream.prototype = new Stream();
12411CoalesceStream.prototype.flush = function(flushSource) {
12412  var
12413    offset = 0,
12414    event = {
12415      captions: [],
12416      metadata: [],
12417      info: {}
12418    },
12419    caption,
12420    id3,
12421    initSegment,
12422    timelineStartPts = 0,
12423    i;
12424
12425  if (this.pendingTracks.length < this.numberOfTracks) {
12426    if (flushSource !== 'VideoSegmentStream' &&
12427        flushSource !== 'AudioSegmentStream') {
12428      // Return because we haven't received a flush from a data-generating
12429      // portion of the segment (meaning that we have only recieved meta-data
12430      // or captions.)
12431      return;
12432    } else if (this.remuxTracks) {
12433      // Return until we have enough tracks from the pipeline to remux (if we
12434      // are remuxing audio and video into a single MP4)
12435      return;
12436    } else if (this.pendingTracks.length === 0) {
12437      // In the case where we receive a flush without any data having been
12438      // received we consider it an emitted track for the purposes of coalescing
12439      // `done` events.
12440      // We do this for the case where there is an audio and video track in the
12441      // segment but no audio data. (seen in several playlists with alternate
12442      // audio tracks and no audio present in the main TS segments.)
12443      this.emittedTracks++;
12444
12445      if (this.emittedTracks >= this.numberOfTracks) {
12446        this.trigger('done');
12447        this.emittedTracks = 0;
12448      }
12449      return;
12450    }
12451  }
12452
12453  if (this.videoTrack) {
12454    timelineStartPts = this.videoTrack.timelineStartInfo.pts;
12455    VIDEO_PROPERTIES.forEach(function(prop) {
12456      event.info[prop] = this.videoTrack[prop];
12457    }, this);
12458  } else if (this.audioTrack) {
12459    timelineStartPts = this.audioTrack.timelineStartInfo.pts;
12460    AUDIO_PROPERTIES.forEach(function(prop) {
12461      event.info[prop] = this.audioTrack[prop];
12462    }, this);
12463  }
12464
12465  if (this.pendingTracks.length === 1) {
12466    event.type = this.pendingTracks[0].type;
12467  } else {
12468    event.type = 'combined';
12469  }
12470
12471  this.emittedTracks += this.pendingTracks.length;
12472
12473  initSegment = mp4.initSegment(this.pendingTracks);
12474
12475  // Create a new typed array to hold the init segment
12476  event.initSegment = new Uint8Array(initSegment.byteLength);
12477
12478  // Create an init segment containing a moov
12479  // and track definitions
12480  event.initSegment.set(initSegment);
12481
12482  // Create a new typed array to hold the moof+mdats
12483  event.data = new Uint8Array(this.pendingBytes);
12484
12485  // Append each moof+mdat (one per track) together
12486  for (i = 0; i < this.pendingBoxes.length; i++) {
12487    event.data.set(this.pendingBoxes[i], offset);
12488    offset += this.pendingBoxes[i].byteLength;
12489  }
12490
12491  // Translate caption PTS times into second offsets into the
12492  // video timeline for the segment
12493  for (i = 0; i < this.pendingCaptions.length; i++) {
12494    caption = this.pendingCaptions[i];
12495    caption.startTime = (caption.startPts - timelineStartPts);
12496    caption.startTime /= 90e3;
12497    caption.endTime = (caption.endPts - timelineStartPts);
12498    caption.endTime /= 90e3;
12499    event.captions.push(caption);
12500  }
12501
12502  // Translate ID3 frame PTS times into second offsets into the
12503  // video timeline for the segment
12504  for (i = 0; i < this.pendingMetadata.length; i++) {
12505    id3 = this.pendingMetadata[i];
12506    id3.cueTime = (id3.pts - timelineStartPts);
12507    id3.cueTime /= 90e3;
12508    event.metadata.push(id3);
12509  }
12510  // We add this to every single emitted segment even though we only need
12511  // it for the first
12512  event.metadata.dispatchType = this.metadataStream.dispatchType;
12513
12514  // Reset stream state
12515  this.pendingTracks.length = 0;
12516  this.videoTrack = null;
12517  this.pendingBoxes.length = 0;
12518  this.pendingCaptions.length = 0;
12519  this.pendingBytes = 0;
12520  this.pendingMetadata.length = 0;
12521
12522  // Emit the built segment
12523  this.trigger('data', event);
12524
12525  // Only emit `done` if all tracks have been flushed and emitted
12526  if (this.emittedTracks >= this.numberOfTracks) {
12527    this.trigger('done');
12528    this.emittedTracks = 0;
12529  }
12530};
12531/**
12532 * A Stream that expects MP2T binary data as input and produces
12533 * corresponding media segments, suitable for use with Media Source
12534 * Extension (MSE) implementations that support the ISO BMFF byte
12535 * stream format, like Chrome.
12536 */
12537Transmuxer = function(options) {
12538  var
12539    self = this,
12540    hasFlushed = true,
12541    videoTrack,
12542    audioTrack;
12543
12544  Transmuxer.prototype.init.call(this);
12545
12546  options = options || {};
12547  this.baseMediaDecodeTime = options.baseMediaDecodeTime || 0;
12548  this.transmuxPipeline_ = {};
12549
12550  this.setupAacPipeline = function() {
12551    var pipeline = {};
12552    this.transmuxPipeline_ = pipeline;
12553
12554    pipeline.type = 'aac';
12555    pipeline.metadataStream = new m2ts.MetadataStream();
12556
12557    // set up the parsing pipeline
12558    pipeline.aacStream = new AacStream();
12559    pipeline.audioTimestampRolloverStream = new m2ts.TimestampRolloverStream('audio');
12560    pipeline.timedMetadataTimestampRolloverStream = new m2ts.TimestampRolloverStream('timed-metadata');
12561    pipeline.adtsStream = new AdtsStream();
12562    pipeline.coalesceStream = new CoalesceStream(options, pipeline.metadataStream);
12563    pipeline.headOfPipeline = pipeline.aacStream;
12564
12565    pipeline.aacStream
12566      .pipe(pipeline.audioTimestampRolloverStream)
12567      .pipe(pipeline.adtsStream);
12568    pipeline.aacStream
12569      .pipe(pipeline.timedMetadataTimestampRolloverStream)
12570      .pipe(pipeline.metadataStream)
12571      .pipe(pipeline.coalesceStream);
12572
12573    pipeline.metadataStream.on('timestamp', function(frame) {
12574      pipeline.aacStream.setTimestamp(frame.timeStamp);
12575    });
12576
12577    pipeline.aacStream.on('data', function(data) {
12578      if (data.type === 'timed-metadata' && !pipeline.audioSegmentStream) {
12579        audioTrack = audioTrack || {
12580          timelineStartInfo: {
12581            baseMediaDecodeTime: self.baseMediaDecodeTime
12582          },
12583          codec: 'adts',
12584          type: 'audio'
12585        };
12586        // hook up the audio segment stream to the first track with aac data
12587        pipeline.coalesceStream.numberOfTracks++;
12588        pipeline.audioSegmentStream = new AudioSegmentStream(audioTrack);
12589        // Set up the final part of the audio pipeline
12590        pipeline.adtsStream
12591          .pipe(pipeline.audioSegmentStream)
12592          .pipe(pipeline.coalesceStream);
12593      }
12594    });
12595
12596    // Re-emit any data coming from the coalesce stream to the outside world
12597    pipeline.coalesceStream.on('data', this.trigger.bind(this, 'data'));
12598    // Let the consumer know we have finished flushing the entire pipeline
12599    pipeline.coalesceStream.on('done', this.trigger.bind(this, 'done'));
12600  };
12601
12602  this.setupTsPipeline = function() {
12603    var pipeline = {};
12604    this.transmuxPipeline_ = pipeline;
12605
12606    pipeline.type = 'ts';
12607    pipeline.metadataStream = new m2ts.MetadataStream();
12608
12609    // set up the parsing pipeline
12610    pipeline.packetStream = new m2ts.TransportPacketStream();
12611    pipeline.parseStream = new m2ts.TransportParseStream();
12612    pipeline.elementaryStream = new m2ts.ElementaryStream();
12613    pipeline.videoTimestampRolloverStream = new m2ts.TimestampRolloverStream('video');
12614    pipeline.audioTimestampRolloverStream = new m2ts.TimestampRolloverStream('audio');
12615    pipeline.timedMetadataTimestampRolloverStream = new m2ts.TimestampRolloverStream('timed-metadata');
12616    pipeline.adtsStream = new AdtsStream();
12617    pipeline.h264Stream = new H264Stream();
12618    pipeline.captionStream = new m2ts.CaptionStream();
12619    pipeline.coalesceStream = new CoalesceStream(options, pipeline.metadataStream);
12620    pipeline.headOfPipeline = pipeline.packetStream;
12621
12622    // disassemble MPEG2-TS packets into elementary streams
12623    pipeline.packetStream
12624      .pipe(pipeline.parseStream)
12625      .pipe(pipeline.elementaryStream);
12626
12627    // !!THIS ORDER IS IMPORTANT!!
12628    // demux the streams
12629    pipeline.elementaryStream
12630      .pipe(pipeline.videoTimestampRolloverStream)
12631      .pipe(pipeline.h264Stream);
12632    pipeline.elementaryStream
12633      .pipe(pipeline.audioTimestampRolloverStream)
12634      .pipe(pipeline.adtsStream);
12635
12636    pipeline.elementaryStream
12637      .pipe(pipeline.timedMetadataTimestampRolloverStream)
12638      .pipe(pipeline.metadataStream)
12639      .pipe(pipeline.coalesceStream);
12640
12641    // Hook up CEA-608/708 caption stream
12642    pipeline.h264Stream.pipe(pipeline.captionStream)
12643      .pipe(pipeline.coalesceStream);
12644
12645    pipeline.elementaryStream.on('data', function(data) {
12646      var i;
12647
12648      if (data.type === 'metadata') {
12649        i = data.tracks.length;
12650
12651        // scan the tracks listed in the metadata
12652        while (i--) {
12653          if (!videoTrack && data.tracks[i].type === 'video') {
12654            videoTrack = data.tracks[i];
12655            videoTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime;
12656          } else if (!audioTrack && data.tracks[i].type === 'audio') {
12657            audioTrack = data.tracks[i];
12658            audioTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime;
12659          }
12660        }
12661
12662        // hook up the video segment stream to the first track with h264 data
12663        if (videoTrack && !pipeline.videoSegmentStream) {
12664          pipeline.coalesceStream.numberOfTracks++;
12665          pipeline.videoSegmentStream = new VideoSegmentStream(videoTrack);
12666
12667          pipeline.videoSegmentStream.on('timelineStartInfo', function(timelineStartInfo) {
12668          // When video emits timelineStartInfo data after a flush, we forward that
12669          // info to the AudioSegmentStream, if it exists, because video timeline
12670          // data takes precedence.
12671            if (audioTrack) {
12672              audioTrack.timelineStartInfo = timelineStartInfo;
12673              // On the first segment we trim AAC frames that exist before the
12674              // very earliest DTS we have seen in video because Chrome will
12675              // interpret any video track with a baseMediaDecodeTime that is
12676              // non-zero as a gap.
12677              pipeline.audioSegmentStream.setEarliestDts(timelineStartInfo.dts);
12678            }
12679          });
12680
12681          // Set up the final part of the video pipeline
12682          pipeline.h264Stream
12683            .pipe(pipeline.videoSegmentStream)
12684            .pipe(pipeline.coalesceStream);
12685        }
12686
12687        if (audioTrack && !pipeline.audioSegmentStream) {
12688          // hook up the audio segment stream to the first track with aac data
12689          pipeline.coalesceStream.numberOfTracks++;
12690          pipeline.audioSegmentStream = new AudioSegmentStream(audioTrack);
12691
12692          // Set up the final part of the audio pipeline
12693          pipeline.adtsStream
12694            .pipe(pipeline.audioSegmentStream)
12695            .pipe(pipeline.coalesceStream);
12696        }
12697      }
12698    });
12699
12700    // Re-emit any data coming from the coalesce stream to the outside world
12701    pipeline.coalesceStream.on('data', this.trigger.bind(this, 'data'));
12702    // Let the consumer know we have finished flushing the entire pipeline
12703    pipeline.coalesceStream.on('done', this.trigger.bind(this, 'done'));
12704  };
12705
12706  // hook up the segment streams once track metadata is delivered
12707  this.setBaseMediaDecodeTime = function(baseMediaDecodeTime) {
12708    var pipeline = this.transmuxPipeline_;
12709
12710    this.baseMediaDecodeTime = baseMediaDecodeTime;
12711    if (audioTrack) {
12712      audioTrack.timelineStartInfo.dts = undefined;
12713      audioTrack.timelineStartInfo.pts = undefined;
12714      clearDtsInfo(audioTrack);
12715      audioTrack.timelineStartInfo.baseMediaDecodeTime = baseMediaDecodeTime;
12716    }
12717    if (videoTrack) {
12718      if (pipeline.videoSegmentStream) {
12719        pipeline.videoSegmentStream.gopCache_ = [];
12720      }
12721      videoTrack.timelineStartInfo.dts = undefined;
12722      videoTrack.timelineStartInfo.pts = undefined;
12723      clearDtsInfo(videoTrack);
12724      videoTrack.timelineStartInfo.baseMediaDecodeTime = baseMediaDecodeTime;
12725    }
12726  };
12727
12728  // feed incoming data to the front of the parsing pipeline
12729  this.push = function(data) {
12730    if (hasFlushed) {
12731      var isAac = isLikelyAacData(data);
12732
12733      if (isAac && this.transmuxPipeline_.type !== 'aac') {
12734        this.setupAacPipeline();
12735      } else if (!isAac && this.transmuxPipeline_.type !== 'ts') {
12736        this.setupTsPipeline();
12737      }
12738      hasFlushed = false;
12739    }
12740    this.transmuxPipeline_.headOfPipeline.push(data);
12741  };
12742
12743  // flush any buffered data
12744  this.flush = function() {
12745      hasFlushed = true;
12746    // Start at the top of the pipeline and flush all pending work
12747    this.transmuxPipeline_.headOfPipeline.flush();
12748  };
12749};
12750Transmuxer.prototype = new Stream();
12751
12752module.exports = {
12753  Transmuxer: Transmuxer,
12754  VideoSegmentStream: VideoSegmentStream,
12755  AudioSegmentStream: AudioSegmentStream,
12756  AUDIO_PROPERTIES: AUDIO_PROPERTIES,
12757  VIDEO_PROPERTIES: VIDEO_PROPERTIES
12758};
12759
12760},{"../aac":67,"../codecs/adts.js":68,"../codecs/h264":69,"../m2ts/m2ts.js":74,"../utils/stream.js":83,"./mp4-generator.js":79}],82:[function(require,module,exports){
12761'use strict';
12762
12763var ExpGolomb;
12764
12765/**
12766 * Parser for exponential Golomb codes, a variable-bitwidth number encoding
12767 * scheme used by h264.
12768 */
12769ExpGolomb = function(workingData) {
12770  var
12771    // the number of bytes left to examine in workingData
12772    workingBytesAvailable = workingData.byteLength,
12773
12774    // the current word being examined
12775    workingWord = 0, // :uint
12776
12777    // the number of bits left to examine in the current word
12778    workingBitsAvailable = 0; // :uint;
12779
12780  // ():uint
12781  this.length = function() {
12782    return (8 * workingBytesAvailable);
12783  };
12784
12785  // ():uint
12786  this.bitsAvailable = function() {
12787    return (8 * workingBytesAvailable) + workingBitsAvailable;
12788  };
12789
12790  // ():void
12791  this.loadWord = function() {
12792    var
12793      position = workingData.byteLength - workingBytesAvailable,
12794      workingBytes = new Uint8Array(4),
12795      availableBytes = Math.min(4, workingBytesAvailable);
12796
12797    if (availableBytes === 0) {
12798      throw new Error('no bytes available');
12799    }
12800
12801    workingBytes.set(workingData.subarray(position,
12802                                          position + availableBytes));
12803    workingWord = new DataView(workingBytes.buffer).getUint32(0);
12804
12805    // track the amount of workingData that has been processed
12806    workingBitsAvailable = availableBytes * 8;
12807    workingBytesAvailable -= availableBytes;
12808  };
12809
12810  // (count:int):void
12811  this.skipBits = function(count) {
12812    var skipBytes; // :int
12813    if (workingBitsAvailable > count) {
12814      workingWord          <<= count;
12815      workingBitsAvailable -= count;
12816    } else {
12817      count -= workingBitsAvailable;
12818      skipBytes = Math.floor(count / 8);
12819
12820      count -= (skipBytes * 8);
12821      workingBytesAvailable -= skipBytes;
12822
12823      this.loadWord();
12824
12825      workingWord <<= count;
12826      workingBitsAvailable -= count;
12827    }
12828  };
12829
12830  // (size:int):uint
12831  this.readBits = function(size) {
12832    var
12833      bits = Math.min(workingBitsAvailable, size), // :uint
12834      valu = workingWord >>> (32 - bits); // :uint
12835    // if size > 31, handle error
12836    workingBitsAvailable -= bits;
12837    if (workingBitsAvailable > 0) {
12838      workingWord <<= bits;
12839    } else if (workingBytesAvailable > 0) {
12840      this.loadWord();
12841    }
12842
12843    bits = size - bits;
12844    if (bits > 0) {
12845      return valu << bits | this.readBits(bits);
12846    }
12847    return valu;
12848  };
12849
12850  // ():uint
12851  this.skipLeadingZeros = function() {
12852    var leadingZeroCount; // :uint
12853    for (leadingZeroCount = 0; leadingZeroCount < workingBitsAvailable; ++leadingZeroCount) {
12854      if ((workingWord & (0x80000000 >>> leadingZeroCount)) !== 0) {
12855        // the first bit of working word is 1
12856        workingWord <<= leadingZeroCount;
12857        workingBitsAvailable -= leadingZeroCount;
12858        return leadingZeroCount;
12859      }
12860    }
12861
12862    // we exhausted workingWord and still have not found a 1
12863    this.loadWord();
12864    return leadingZeroCount + this.skipLeadingZeros();
12865  };
12866
12867  // ():void
12868  this.skipUnsignedExpGolomb = function() {
12869    this.skipBits(1 + this.skipLeadingZeros());
12870  };
12871
12872  // ():void
12873  this.skipExpGolomb = function() {
12874    this.skipBits(1 + this.skipLeadingZeros());
12875  };
12876
12877  // ():uint
12878  this.readUnsignedExpGolomb = function() {
12879    var clz = this.skipLeadingZeros(); // :uint
12880    return this.readBits(clz + 1) - 1;
12881  };
12882
12883  // ():int
12884  this.readExpGolomb = function() {
12885    var valu = this.readUnsignedExpGolomb(); // :int
12886    if (0x01 & valu) {
12887      // the number is odd if the low order bit is set
12888      return (1 + valu) >>> 1;
12888 // add 1 to make it even, and divide by 2
12889    }
12890    return -1 * (valu >>> 1); // divide by two then make it negative
12891  };
12892
12893  // Some convenience functions
12894  // :Boolean
12895  this.readBoolean = function() {
12896    return this.readBits(1) === 1;
12897  };
12898
12899  // ():int
12900  this.readUnsignedByte = function() {
12901    return this.readBits(8);
12902  };
12903
12904  this.loadWord();
12905};
12906
12907module.exports = ExpGolomb;
12908
12909},{}],83:[function(require,module,exports){
12910/**
12911 * mux.js
12912 *
12913 * Copyright (c) 2014 Brightcove
12914 * All rights reserved.
12915 *
12916 * A lightweight readable stream implemention that handles event dispatching.
12917 * Objects that inherit from streams should call init in their constructors.
12918 */
12919'use strict';
12920
12921var Stream = function() {
12922  this.init = function() {
12923    var listeners = {};
12924    /**
12925     * Add a listener for a specified event type.
12926     * @param type {string} the event name
12927     * @param listener {function} the callback to be invoked when an event of
12928     * the specified type occurs
12929     */
12930    this.on = function(type, listener) {
12931      if (!listeners[type]) {
12932        listeners[type] = [];
12933      }
12934      listeners[type] = listeners[type].concat(listener);
12935    };
12936    /**
12937     * Remove a listener for a specified event type.
12938     * @param type {string} the event name
12939     * @param listener {function} a function previously registered for this
12940     * type of event through `on`
12941     */
12942    this.off = function(type, listener) {
12943      var index;
12944      if (!listeners[type]) {
12945        return false;
12946      }
12947      index = listeners[type].indexOf(listener);
12948      listeners[type] = listeners[type].slice();
12949      listeners[type].splice(index, 1);
12950      return index > -1;
12951    };
12952    /**
12953     * Trigger an event of the specified type on this stream. Any additional
12954     * arguments to this function are passed as parameters to event listeners.
12955     * @param type {string} the event name
12956     */
12957    this.trigger = function(type) {
12958      var callbacks, i, length, args;
12959      callbacks = listeners[type];
12960      if (!callbacks) {
12961        return;
12962      }
12963      // Slicing the arguments on every invocation of this method
12964      // can add a significant amount of overhead. Avoid the
12965      // intermediate object creation for the common case of a
12966      // single callback argument
12967      if (arguments.length === 2) {
12968        length = callbacks.length;
12969        for (i = 0; i < length; ++i) {
12970          callbacks[i].call(this, arguments[1]);
12971        }
12972      } else {
12973        args = [];
12974        i = arguments.length;
12975        for (i = 1; i < arguments.length; ++i) {
12976          args.push(arguments[i]);
12977        }
12978        length = callbacks.length;
12979        for (i = 0; i < length; ++i) {
12980          callbacks[i].apply(this, args);
12981        }
12982      }
12983    };
12984    /**
12985     * Destroys the stream and cleans up.
12986     */
12987    this.dispose = function() {
12988      listeners = {};
12989    };
12990  };
12991};
12992
12993/**
12994 * Forwards all `data` events on this stream to the destination stream. The
12995 * destination stream should provide a method `push` to receive the data
12996 * events as they arrive.
12997 * @param destination {stream} the stream that will receive all `data` events
12998 * @param autoFlush {boolean} if false, we will not call `flush` on the destination
12999 *                            when the current stream emits a 'done' event
13000 * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
13001 */
13002Stream.prototype.pipe = function(destination) {
13003  this.on('data', function(data) {
13004    destination.push(data);
13005  });
13006
13007  this.on('done', function(flushSource) {
13008    destination.flush(flushSource);
13009  });
13010
13011  return destination;
13012};
13013
13014// Default stream functions that are expected to be overridden to perform
13015// actual work. These are provided by the prototype as a sort of no-op
13016// implementation so that we don't have to check for their existence in the
13017// `pipe` function above.
13018Stream.prototype.push = function(data) {
13019  this.trigger('data', data);
13020};
13021
13022Stream.prototype.flush = function(flushSource) {
13023  this.trigger('done', flushSource);
13024};
13025
13026module.exports = Stream;
13027
13028},{}],84:[function(require,module,exports){
13029(function (global){
13030/**
13031 * @file add-text-track-data.js
13032 */
13033'use strict';
13034
13035Object.defineProperty(exports, '__esModule', {
13036  value: true
13037});
13038
13039function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
13040
13041var _globalWindow = require('global/window');
13042
13043var _globalWindow2 = _interopRequireDefault(_globalWindow);
13044
13045var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
13046
13047var _videoJs2 = _interopRequireDefault(_videoJs);
13048
13049/**
13050 * Define properties on a cue for backwards compatability,
13051 * but warn the user that the way that they are using it
13052 * is depricated and will be removed at a later date.
13053 *
13054 * @param {Cue} cue the cue to add the properties on
13055 * @private
13056 */
13057var deprecateOldCue = function deprecateOldCue(cue) {
13058  Object.defineProperties(cue.frame, {
13059    id: {
13060      get: function get() {
13061        _videoJs2['default'].log.warn('cue.frame.id is deprecated. Use cue.value.key instead.');
13062        return cue.value.key;
13063      }
13064    },
13065    value: {
13066      get: function get() {
13067        _videoJs2['default'].log.warn('cue.frame.value is deprecated. Use cue.value.data instead.');
13068        return cue.value.data;
13069      }
13070    },
13071    privateData: {
13072      get: function get() {
13073        _videoJs2['default'].log.warn('cue.frame.privateData is deprecated. Use cue.value.data instead.');
13074        return cue.value.data;
13075      }
13076    }
13077  });
13078};
13079
13080var durationOfVideo = function durationOfVideo(duration) {
13081  var dur = undefined;
13082
13083  if (isNaN(duration) || Math.abs(duration) === Infinity) {
13084    dur = Number.MAX_VALUE;
13085  } else {
13086    dur = duration;
13087  }
13088  return dur;
13089};
13090/**
13091 * Add text track data to a source handler given the captions and
13092 * metadata from the buffer.
13093 *
13094 * @param {Object} sourceHandler the flash or virtual source buffer
13095 * @param {Array} captionArray an array of caption data
13096 * @param {Array} cue an array of meta data
13097 * @private
13098 */
13099var addTextTrackData = function addTextTrackData(sourceHandler, captionArray, metadataArray) {
13100  var Cue = _globalWindow2['default'].WebKitDataCue || _globalWindow2['default'].VTTCue;
13101
13102  if (captionArray) {
13103    captionArray.forEach(function (caption) {
13104      this.inbandTextTrack_.addCue(new Cue(caption.startTime + this.timestampOffset, caption.endTime + this.timestampOffset, caption.text));
13105    }, sourceHandler);
13106  }
13107
13108  if (metadataArray) {
13109    var videoDuration = durationOfVideo(sourceHandler.mediaSource_.duration);
13110
13111    metadataArray.forEach(function (metadata) {
13112      var time = metadata.cueTime + this.timestampOffset;
13113
13114      metadata.frames.forEach(function (frame) {
13115        var cue = new Cue(time, time, frame.value || frame.url || frame.data || '');
13116
13117        cue.frame = frame;
13118        cue.value = frame;
13119        deprecateOldCue(cue);
13120
13121        this.metadataTrack_.addCue(cue);
13122      }, this);
13123    }, sourceHandler);
13124
13125    // Updating the metadeta cues so that
13126    // the endTime of each cue is the startTime of the next cue
13127    // the endTime of last cue is the duration of the video
13128    if (sourceHandler.metadataTrack_ && sourceHandler.metadataTrack_.cues && sourceHandler.metadataTrack_.cues.length) {
13129      var cues = sourceHandler.metadataTrack_.cues;
13130      var cuesArray = [];
13131
13132      for (var j = 0; j < cues.length; j++) {
13133        cuesArray.push(cues[j]);
13134      }
13135      cuesArray.sort(function (first, second) {
13136        return first.startTime - second.startTime;
13137      });
13138
13139      for (var i = 0; i < cuesArray.length - 1; i++) {
13140        if (cuesArray[i].endTime !== cuesArray[i + 1].startTime) {
13141          cuesArray[i].endTime = cuesArray[i + 1].startTime;
13142        }
13143      }
13144      cuesArray[cuesArray.length - 1].endTime = videoDuration;
13145    }
13146  }
13147};
13148
13149exports['default'] = {
13150  addTextTrackData: addTextTrackData,
13151  durationOfVideo: durationOfVideo
13152};
13153module.exports = exports['default'];
13154}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
13155},{"global/window":25}],85:[function(require,module,exports){
13156/**
13157 * @file codec-utils.js
13158 */
13159
13160/**
13161 * Check if a codec string refers to an audio codec.
13162 *
13163 * @param {String} codec codec string to check
13164 * @return {Boolean} if this is an audio codec
13165 * @private
13166 */
13167'use strict';
13168
13169Object.defineProperty(exports, '__esModule', {
13170  value: true
13171});
13172var isAudioCodec = function isAudioCodec(codec) {
13173  return (/mp4a\.\d+.\d+/i.test(codec)
13174  );
13175};
13176
13177/**
13178 * Check if a codec string refers to a video codec.
13179 *
13180 * @param {String} codec codec string to check
13181 * @return {Boolean} if this is a video codec
13182 * @private
13183 */
13184var isVideoCodec = function isVideoCodec(codec) {
13185  return (/avc1\.[\da-f]+/i.test(codec)
13186  );
13187};
13188
13189/**
13190 * Parse a content type header into a type and parameters
13191 * object
13192 *
13193 * @param {String} type the content type header
13194 * @return {Object} the parsed content-type
13195 * @private
13196 */
13197var parseContentType = function parseContentType(type) {
13198  var object = { type: '', parameters: {} };
13199  var parameters = type.trim().split(';');
13200
13201  // first parameter should always be content-type
13202  object.type = parameters.shift().trim();
13203  parameters.forEach(function (parameter) {
13204    var pair = parameter.trim().split('=');
13205
13206    if (pair.length > 1) {
13207      var _name = pair[0].replace(/"/g, '').trim();
13208      var value = pair[1].replace(/"/g, '').trim();
13209
13210      object.parameters[_name] = value;
13211    }
13212  });
13213
13214  return object;
13215};
13216
13217exports['default'] = {
13218  isAudioCodec: isAudioCodec,
13219  parseContentType: parseContentType,
13220  isVideoCodec: isVideoCodec
13221};
13222module.exports = exports['default'];
13223},{}],86:[function(require,module,exports){
13224/**
13225 * @file create-text-tracks-if-necessary.js
13226 */
13227
13228/**
13229 * Create text tracks on video.js if they exist on a segment.
13230 *
13231 * @param {Object} sourceBuffer the VSB or FSB
13232 * @param {Object} mediaSource the HTML or Flash media source
13233 * @param {Object} segment the segment that may contain the text track
13234 * @private
13235 */
13236'use strict';
13237
13238Object.defineProperty(exports, '__esModule', {
13239  value: true
13240});
13241var createTextTracksIfNecessary = function createTextTracksIfNecessary(sourceBuffer, mediaSource, segment) {
13242  // create an in-band caption track if one is present in the segment
13243  if (segment.captions && segment.captions.length && !sourceBuffer.inbandTextTrack_) {
13244    sourceBuffer.inbandTextTrack_ = mediaSource.player_.addTextTrack('captions', 'cc1');
13245  }
13246
13247  if (segment.metadata && segment.metadata.length && !sourceBuffer.metadataTrack_) {
13248    sourceBuffer.metadataTrack_ = mediaSource.player_.addTextTrack('metadata', 'Timed Metadata');
13249    sourceBuffer.metadataTrack_.inBandMetadataTrackDispatchType = segment.metadata.dispatchType;
13250  }
13251};
13252
13253exports['default'] = createTextTracksIfNecessary;
13254module.exports = exports['default'];
13255},{}],87:[function(require,module,exports){
13256/**
13257 * @file flash-constants.js
13258 */
13259/**
13260 * The maximum size in bytes for append operations to the video.js
13261 * SWF. Calling through to Flash blocks and can be expensive so
13262 * tuning this parameter may improve playback on slower
13263 * systems. There are two factors to consider:
13264 * - Each interaction with the SWF must be quick or you risk dropping
13265 * video frames. To maintain 60fps for the rest of the page, each append
13266 * must not  take longer than 16ms. Given the likelihood that the page
13267 * will be executing more javascript than just playback, you probably
13268 * want to aim for less than 8ms. We aim for just 4ms.
13269 * - Bigger appends significantly increase throughput. The total number of
13270 * bytes over time delivered to the SWF must exceed the video bitrate or
13271 * playback will stall.
13272 *
13273 * We adaptively tune the size of appends to give the best throughput
13274 * possible given the performance of the system. To do that we try to append
13275 * as much as possible in TIME_PER_TICK and while tuning the size of appends
13276 * dynamically so that we only append about 4-times in that 4ms span.
13277 *
13278 * The reason we try to keep the number of appends around four is due to
13279 * externalities such as Flash load and garbage collection that are highly
13280 * variable and having 4 iterations allows us to exit the loop early if
13281 * an iteration takes longer than expected.
13282 *
13283 * @private
13284 */
13285"use strict";
13286
13287Object.defineProperty(exports, "__esModule", {
13288  value: true
13289});
13290var flashConstants = {
13291  TIME_BETWEEN_TICKS: Math.floor(1000 / 500),
13292  TIME_PER_TICK: Math.floor(1000 / 100),
13293  // 1kb
13294  BYTES_PER_CHUNK: 4 * 1024,
13295  MIN_CHUNK: 4096,
13296  MAX_CHUNK: 4 * 1024 * 1024
13297};
13298
13299exports["default"] = flashConstants;
13300module.exports = exports["default"];
13301},{}],88:[function(require,module,exports){
13302(function (global){
13303/**
13304 * @file flash-media-source.js
13305 */
13306'use strict';
13307
13308Object.defineProperty(exports, '__esModule', {
13309  value: true
13310});
13311
13312var _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; }; })();
13313
13314var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
13315
13316function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
13317
13318function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
13319
13320function _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; }
13321
13322var _globalDocument = require('global/document');
13323
13324var _globalDocument2 = _interopRequireDefault(_globalDocument);
13325
13326var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
13327
13328var _videoJs2 = _interopRequireDefault(_videoJs);
13329
13330var _flashSourceBuffer = require('./flash-source-buffer');
13331
13332var _flashSourceBuffer2 = _interopRequireDefault(_flashSourceBuffer);
13333
13334var _flashConstants = require('./flash-constants');
13335
13336var _flashConstants2 = _interopRequireDefault(_flashConstants);
13337
13338var _codecUtils = require('./codec-utils');
13339
13340/**
13341 * A flash implmentation of HTML MediaSources and a polyfill
13342 * for browsers that don't support native or HTML MediaSources..
13343 *
13344 * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
13345 * @class FlashMediaSource
13346 * @extends videojs.EventTarget
13347 */
13348
13349var FlashMediaSource = (function (_videojs$EventTarget) {
13350  _inherits(FlashMediaSource, _videojs$EventTarget);
13351
13352  function FlashMediaSource() {
13353    var _this = this;
13354
13355    _classCallCheck(this, FlashMediaSource);
13356
13357    _get(Object.getPrototypeOf(FlashMediaSource.prototype), 'constructor', this).call(this);
13358    this.sourceBuffers = [];
13359    this.readyState = 'closed';
13360
13361    this.on(['sourceopen', 'webkitsourceopen'], function (event) {
13362      // find the swf where we will push media data
13363      _this.swfObj = _globalDocument2['default'].getElementById(event.swfId);
13364      _this.player_ = (0, _videoJs2['default'])(_this.swfObj.parentNode);
13365      _this.tech_ = _this.swfObj.tech;
13366      _this.readyState = 'open';
13367
13368      _this.tech_.on('seeking', function () {
13369        var i = _this.sourceBuffers.length;
13370
13371        while (i--) {
13372          _this.sourceBuffers[i].abort();
13373        }
13374      });
13375
13376      // trigger load events
13377      if (_this.swfObj) {
13378        _this.swfObj.vjs_load();
13379      }
13380    });
13381  }
13382
13383  /**
13384    * Set or return the presentation duration.
13385    *
13386    * @param {Double} value the duration of the media in seconds
13387    * @param {Double} the current presentation duration
13388    * @link http://www.w3.org/TR/media-source/#widl-MediaSource-duration
13389    */
13390
13391  /**
13392   * We have this function so that the html and flash interfaces
13393   * are the same.
13394   *
13395   * @private
13396   */
13397
13398  _createClass(FlashMediaSource, [{
13399    key: 'addSeekableRange_',
13400    value: function addSeekableRange_() {}
13401    // intentional no-op
13402
13403    /**
13404     * Create a new flash source buffer and add it to our flash media s
13404ource.
13405     *
13406     * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/addSourceBuffer
13407     * @param {String} type the content-type of the source
13408     * @return {Object} the flash source buffer
13409     */
13410
13411  }, {
13412    key: 'addSourceBuffer',
13413    value: function addSourceBuffer(type) {
13414      var parsedType = (0, _codecUtils.parseContentType)(type);
13415      var sourceBuffer = undefined;
13416
13417      // if this is an FLV type, we'll push data to flash
13418      if (parsedType.type === 'video/mp2t') {
13419        // Flash source buffers
13420        sourceBuffer = new _flashSourceBuffer2['default'](this);
13421      } else {
13422        throw new Error('NotSupportedError (Video.js)');
13423      }
13424
13425      this.sourceBuffers.push(sourceBuffer);
13426      return sourceBuffer;
13427    }
13428
13429    /**
13430     * Signals the end of the stream.
13431     *
13432     * @link https://w3c.github.io/media-source/#widl-MediaSource-endOfStream-void-EndOfStreamError-error
13433     * @param {String=} error Signals that a playback error
13434     * has occurred. If specified, it must be either "network" or
13435     * "decode".
13436     */
13437  }, {
13438    key: 'endOfStream',
13439    value: function endOfStream(error) {
13440      if (error === 'network') {
13441        // MEDIA_ERR_NETWORK
13442        this.tech_.error(2);
13443      } else if (error === 'decode') {
13444        // MEDIA_ERR_DECODE
13445        this.tech_.error(3);
13446      }
13447      if (this.readyState !== 'ended') {
13448        this.readyState = 'ended';
13449        this.swfObj.vjs_endOfStream();
13450      }
13451    }
13452  }]);
13453
13454  return FlashMediaSource;
13455})(_videoJs2['default'].EventTarget);
13456
13457exports['default'] = FlashMediaSource;
13458try {
13459  Object.defineProperty(FlashMediaSource.prototype, 'duration', {
13460    /**
13461     * Return the presentation duration.
13462     *
13463     * @return {Double} the duration of the media in seconds
13464     * @link http://www.w3.org/TR/media-source/#widl-MediaSource-duration
13465     */
13466    get: function get() {
13467      if (!this.swfObj) {
13468        return NaN;
13469      }
13470      // get the current duration from the SWF
13471      return this.swfObj.vjs_getProperty('duration');
13472    },
13473    /**
13474     * Set the presentation duration.
13475     *
13476     * @param {Double} value the duration of the media in seconds
13477     * @return {Double} the duration of the media in seconds
13478     * @link http://www.w3.org/TR/media-source/#widl-MediaSource-duration
13479     */
13480    set: function set(value) {
13481      var i = undefined;
13482      var oldDuration = this.swfObj.vjs_getProperty('duration');
13483
13484      this.swfObj.vjs_setProperty('duration', value);
13485
13486      if (value < oldDuration) {
13487        // In MSE, this triggers the range removal algorithm which causes
13488        // an update to occur
13489        for (i = 0; i < this.sourceBuffers.length; i++) {
13490          this.sourceBuffers[i].remove(value, oldDuration);
13491        }
13492      }
13493
13494      return value;
13495    }
13496  });
13497} catch (e) {
13498  // IE8 throws if defineProperty is called on a non-DOM node. We
13499  // don't support IE8 but we shouldn't throw an error if loaded
13500  // there.
13501  FlashMediaSource.prototype.duration = NaN;
13502}
13503
13504for (var property in _flashConstants2['default']) {
13505  FlashMediaSource[property] = _flashConstants2['default'][property];
13506}
13507module.exports = exports['default'];
13508}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
13509},{"./codec-utils":85,"./flash-constants":87,"./flash-source-buffer":89,"global/document":24}],89:[function(require,module,exports){
13510(function (global){
13511/**
13512 * @file flash-source-buffer.js
13513 */
13514'use strict';
13515
13516Object.defineProperty(exports, '__esModule', {
13517  value: true
13518});
13519
13520var _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; }; })();
13521
13522var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
13523
13524function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
13525
13526function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
13527
13528function _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, { c
13528onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
13529
13530var _globalWindow = require('global/window');
13531
13532var _globalWindow2 = _interopRequireDefault(_globalWindow);
13533
13534var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
13535
13536var _videoJs2 = _interopRequireDefault(_videoJs);
13537
13538var _muxJsLibFlv = require('mux.js/lib/flv');
13539
13540var _muxJsLibFlv2 = _interopRequireDefault(_muxJsLibFlv);
13541
13542var _removeCuesFromTrack = require('./remove-cues-from-track');
13543
13544var _removeCuesFromTrack2 = _interopRequireDefault(_removeCuesFromTrack);
13545
13546var _createTextTracksIfNecessary = require('./create-text-tracks-if-necessary');
13547
13548var _createTextTracksIfNecessary2 = _interopRequireDefault(_createTextTracksIfNecessary);
13549
13550var _addTextTrackData = require('./add-text-track-data');
13551
13552var _flashConstants = require('./flash-constants');
13553
13554var _flashConstants2 = _interopRequireDefault(_flashConstants);
13555
13556/**
13557 * A wrapper around the setTimeout function that uses
13558 * the flash constant time between ticks value.
13559 *
13560 * @param {Function} func the function callback to run
13561 * @private
13562 */
13563var scheduleTick = function scheduleTick(func) {
13564  // Chrome doesn't invoke requestAnimationFrame callbacks
13565  // in background tabs, so use setTimeout.
13566  _globalWindow2['default'].setTimeout(func, _flashConstants2['default'].TIME_BETWEEN_TICKS);
13567};
13568
13569/**
13570 * Round a number to a specified number of places much like
13571 * toFixed but return a number instead of a string representation.
13572 *
13573 * @param {Number} num A number
13574 * @param {Number} places The number of decimal places which to
13575 * round
13576 * @private
13577 */
13578var toDecimalPlaces = function toDecimalPlaces(num, places) {
13579  if (typeof places !== 'number' || places < 0) {
13580    places = 0;
13581  }
13582
13583  var scale = Math.pow(10, places);
13584
13585  return Math.round(num * scale) / scale;
13586};
13587
13588/**
13589 * A SourceBuffer implementation for Flash rather than HTML.
13590 *
13591 * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
13592 * @param {Object} mediaSource the flash media source
13593 * @class FlashSourceBuffer
13594 * @extends videojs.EventTarget
13595 */
13596
13597var FlashSourceBuffer = (function (_videojs$EventTarget) {
13598  _inherits(FlashSourceBuffer, _videojs$EventTarget);
13599
13600  function FlashSourceBuffer(mediaSource) {
13601    var _this = this;
13602
13603    _classCallCheck(this, FlashSourceBuffer);
13604
13605    _get(Object.getPrototypeOf(FlashSourceBuffer.prototype), 'constructor', this).call(this);
13606    var encodedHeader = undefined;
13607
13608    // Start off using the globally defined value but refine
13609    // as we append data into flash
13610    this.chunkSize_ = _flashConstants2['default'].BYTES_PER_CHUNK;
13611
13612    // byte arrays queued to be appended
13613    this.buffer_ = [];
13614
13615    // the total number of queued bytes
13616    this.bufferSize_ = 0;
13617
13618    // to be able to determine the correct position to seek to, we
13619    // need to retain information about the mapping between the
13620    // media timeline and PTS values
13621    this.basePtsOffset_ = NaN;
13622
13623    this.mediaSource_ = mediaSource;
13624
13625    // indicates whether the asynchronous continuation of an operation
13626    // is still being processed
13627    // see https://w3c.github.io/media-source/#widl-SourceBuffer-updating
13628    this.updating = false;
13629    this.timestampOffset_ = 0;
13630
13631    // TS to FLV transmuxer
13632    this.segmentParser_ = new _muxJsLibFlv2['default'].Transmuxer();
13633    this.segmentParser_.on('data', this.receiveBuffer_.bind(this));
13634    encodedHeader = _globalWindow2['default'].btoa(String.fromCharCode.apply(null, Array.prototype.slice.call(this.segmentParser_.getFlvHeader())));
13635    this.mediaSource_.swfObj.vjs_appendBuffer(encodedHeader);
13636
13637    this.one('updateend', function () {
13638      _this.mediaSource_.tech_.trigger('loadedmetadata');
13639    });
13640
13641    Object.defineProperty(this, 'timestampOffset', {
13642      get: function get() {
13643        return this.timestampOffset_;
13644      },
13645      set: function set(val) {
13646        if (typeof val === 'number' && val >= 0) {
13647          this.timestampOffset_ = val;
13648          this.segmentParser_ = new _muxJsLibFlv2['default'].Transmuxer();
13649          this.segmentParser_.on('data', this.receiveBuffer_.bind(this));
13650          // We have to tell flash to expect a discontinuity
13651          this.mediaSource_.swfObj.vjs_discontinuity();
13652          // the media <-> PTS mapping must be re-established after
13653          // the discontinuity
13654          this.basePtsOffset_ = NaN;
13655        }
13656      }
13657    });
13658
13659    Object.defineProperty(this, 'buffered', {
13660      get: function get() {
13661        if (!this.mediaSource_ || !this.mediaSource_.swfObj || !('vjs_getProperty' in this.mediaSource_.swfObj)) {
13662          return _videoJs2['default'].createTimeRange();
13663        }
13664
13665        var buffered = this.mediaSource_.swfObj.vjs_getProperty('buffered');
13666
13667        if (buffered && buffered.length) {
13668          buffered[0][0] = toDecimalPlaces(buffered[0][0], 3);
13669          buffered[0][1] = toDecimalPlaces(buffered[0][1], 3);
13670        }
13671        return _videoJs2['default'].createTimeRanges(buffered);
13672      }
13673    });
13674
13675    // On a seek we remove all text track data since flash has no concept
13676    // of a buffered-range and everything else is reset on seek
13677    this.mediaSource_.player_.on('seeked', function () {
13678      (0, _removeCuesFromTrack2['default'])(0, Infinity, _this.metadataTrack_);
13679      (0, _removeCuesFromTrack2['default'])(0, Infinity, _this.inbandTextTrack_);
13680    });
13681  }
13682
13683  /**
13684   * Append bytes to the sourcebuffers buffer, in this case we
13685   * have to append it to swf object.
13686   *
13687   * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/appendBuffer
13688   * @param {Array} bytes
13689   */
13690
13691  _createClass(FlashSourceBuffer, [{
13692    key: 'appendBuffer',
13693    value: function appendBuffer(bytes) {
13694      var _this2 = this;
13695
13696      var error = undefined;
13697      var chunk = 512 * 1024;
13698      var i = 0;
13699
13700      if (this.updating) {
13701        error = new Error('SourceBuffer.append() cannot be called ' + 'while an update is in progress');
13702        error.name = 'InvalidStateError';
13703        error.code = 11;
13704        throw error;
13705      }
13706
13707      this.updating = true;
13708      this.mediaSource_.readyState = 'open';
13709      this.trigger({ type: 'update' });
13710
13711      // this is here to use recursion
13712      var chunkInData = function chunkInData() {
13713        _this2.segmentParser_.push(bytes.subarray(i, i + chunk));
13714        i += chunk;
13715        if (i < bytes.byteLength) {
13716          scheduleTick(chunkInData);
13717        } else {
13718          scheduleTick(_this2.segmentParser_.flush.bind(_this2.segmentParser_));
13719        }
13720      };
13721
13722      chunkInData();
13723    }
13724
13725    /**
13726     * Reset the parser and remove any data queued to be sent to the SWF.
13727     *
13728     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/abort
13729     */
13730  }, {
13731    key: 'abort',
13732    value: function abort() {
13733      this.buffer_ = [];
13734      this.bufferSize_ = 0;
13735      this.mediaSource_.swfObj.vjs_abort();
13736
13737      // report any outstanding updates have ended
13738      if (this.updating) {
13739        this.updating = false;
13740        this.trigger({ type: 'updateend' });
13741      }
13742    }
13743
13744    /**
13745     * Flash cannot remove ranges already buffered in the NetStream
13746     * but seeking clears the buffer entirely. For most purposes,
13747     * having this operation act as a no-op is acceptable.
13748     *
13749     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/remove
13750     * @param {Double} start start of the section to remove
13751     * @param {Double} end end of the section to remove
13752     */
13753  }, {
13754    key: 'remove',
13755    value: function remove(start, end) {
13756      (0, _removeCuesFromTrack2['default'])(start, end, this.metadataTrack_);
13757      (0, _removeCuesFromTrack2['default'])(start, end, this.inbandTextTrack_);
13758      this.trigger({ type: 'update' });
13759      this.trigger({ type: 'updateend' });
13760    }
13761
13762    /**
13763     * Receive a buffer from the flv.
13764     *
13765     * @param {Object} segment
13766     * @private
13767     */
13768  }, {
13769    key: 'receiveBuffer_',
13770    value: function receiveBuffer_(segment) {
13771      var _this3 = this;
13772
13773      // create an in-band caption track if one is present in the segment
13774      (0, _createTextTracksIfNecessary2['default'])(this, this.mediaSource_, segment);
13775      (0, _addTextTrackData.addTextTrackData)(this, segment.captions, segment.metadata);
13776
13777      // Do this asynchronously since convertTagsToData_ can be time consuming
13778      scheduleTick(function () {
13779        var flvBytes = _this3.convertTagsToData_(segment);
13780
13781        if (_this3.buffer_.length === 0) {
13782          scheduleTick(_this3.processBuffer_.bind(_this3));
13783        }
13784
13785        if (flvBytes) {
13786          _this3.buffer_.push(flvBytes);
13787          _this3.bufferSize_ += flvBytes.byteLength;
13788        }
13789      });
13790    }
13791
13792    /**
13793     * Append a portion of the current buffer to the SWF.
13794     *
13795     * @private
13796     */
13797  }, {
13798    key: 'processBuffer_',
13799    value: function processBuffer_() {
13800      var chunk = undefined;
13801      var i = undefined;
13802      var length = undefined;
13803      var binary = undefined;
13804      var b64str = undefined;
13805      var startByte = 0;
13806      var appendIterations = 0;
13807      var startTime = +new Date();
13808      var appendTime = undefined;
13809
13810      if (!this.buffer_.length) {
13811        if (this.updating !== false) {
13812          this.updating = false;
13813          this.trigger({ type: 'updateend' });
13814        }
13815        // do nothing if the buffer is empty
13816        return;
13817      }
13818
13819      do {
13820        appendIterations++;
13821        // concatenate appends up to the max append size
13822        chunk = this.buffer_[0].subarray(startByte, startByte + this.chunkSize_);
13823
13824        // requeue any bytes that won't make it this round
13825        if (chunk.byteLength < this.chunkSize_ || this.buffer_[0].byteLength === startByte + this.chunkSize_) {
13826          startByte = 0;
13827          this.buffer_.shift();
13828        } else {
13829          startByte += this.chunkSize_;
13830        }
13831
13832        this.bufferSize_ -= chunk.byteLength;
13833
13834        // base64 encode the bytes
13835        binary = '';
13836        length = chunk.byteLength;
13837        for (i = 0; i < length; i++) {
13838          binary += String.fromCharCode(chunk[i]);
13839        }
13840        b64str = _globalWindow2['default'].btoa(binary);
13841
13842        // bypass normal ExternalInterface calls and pass xml directly
13843        // IE can be slow by default
13844        this.mediaSource_.swfObj.CallFunction('<invoke name="vjs_appendBuffer"' + 'returntype="javascript"><arguments><string>' + b64str + '</string></arguments></invoke>');
13845        appendTime = new Date() - startTime;
13846      } while (this.buffer_.length && appendTime < _flashConstants2['default'].TIME_PER_TICK);
13847
13848      if (this.buffer_.length && startByte) {
13849        this.buffer_[0] = this.buffer_[0].subarray(startByte);
13850      }
13851
13852      if (appendTime >= _flashConstants2['default'].TIME_PER_TICK) {
13853        // We want to target 4 iterations per time-slot so that gives us
13854        // room to adjust to changes in Flash load and other externalities
13855        // such as garbage collection while still maximizing throughput
13856        this.chunkSize_ = Math.floor(this.chunkSize_ * (appendIterations / 4));
13857      }
13858
13859      // We also make sure that the chunk-size doesn't drop below 1KB or
13860      // go above 1MB as a sanity check
13861      this.chunkSize_ = Math.max(_flashConstants2['default'].MIN_CHUNK, Math.min(this.chunkSize_, _flashConstants2['default'].MAX_CHUNK));
13862
13863      // schedule another append if necessary
13864      if (this.bufferSize_ !== 0) {
13865        scheduleTick(this.processBuffer_.bind(this));
13866      } else {
13867        this.updating = false;
13868        this.trigger({ type: 'updateend' });
13869      }
13870    }
13871
13872    /**
13873     * Turns an array of flv tags into a Uint8Array representing the
13874     * flv data. Also removes any tags that are before the current
13875     * time so that playback begins at or slightly after the right
13876     * place on a seek
13877     *
13878     * @private
13879     * @param {Object} segmentData object of segment data
13880     */
13881  }, {
13882    key: 'convertTagsToData_',
13883    value: function convertTagsToData_(segmentData) {
13884      var segmentByteLength = 0;
13885      var tech = this.mediaSource_.tech_;
13886      var targetPts = 0;
13887      var i = undefined;
13888      var j = undefined;
13889      var segment = undefined;
13890      var filteredTags = [];
13891      var tags = this.getOrderedTags_(segmentData);
13892
13893      // Establish the media timeline to PTS translation if we don't
13894      // have one already
13895      if (isNaN(this.basePtsOffset_) && tags.length) {
13896        this.basePtsOffset_ = tags[0].pts;
13897      }
13898
13899      // Trim to currentTime if it's ahead of buffered or buffered doesn't exist
13900      if (tech.seeking()) {
13901        targetPts = Math.max(targetPts, tech.currentTime() - this.timestampOffset);
13902      }
13903
13904      // PTS values are represented in milliseconds
13905      targetPts *= 1e3;
13906      targetPts += this.basePtsOffset_;
13907
13908      // skip tags with a presentation time less than the seek target
13909      for (i = 0; i < tags.length; i++) {
13910        if (tags[i].pts >= targetPts) {
13911          filteredTags.push(tags[i]);
13912        }
13913      }
13914
13915      if (filteredTags.length === 0) {
13916        return;
13917      }
13918
13919      // concatenate the bytes into a single segment
13920      for (i = 0; i < filteredTags.length; i++) {
13921        segmentByteLength += filteredTags[i].bytes.byteLength;
13922      }
13923      segment = new Uint8Array(segmentByteLength);
13924      for (i = 0, j = 0; i < filteredTags.length; i++) {
13925        segment.set(filteredTags[i].bytes, j);
13926        j += filteredTags[i].bytes.byteLength;
13927      }
13928
13929      return segment;
13930    }
13931
13932    /**
13933     * Assemble the FLV tags in decoder order.
13934     *
13935     * @private
13936     * @param {Object} segmentData object of segment data
13937     */
13938  }, {
13939    key: 'getOrderedTags_',
13940    value: function getOrderedTags_(segmentData) {
13941      var videoTags = segmentData.tags.videoTags;
13942      var audioTags = segmentData.tags.audioTags;
13943      var tag = undefined;
13944      var tags = [];
13945
13946      while (videoTags.length || audioTags.length) {
13947        if (!videoTags.length) {
13948          // only audio tags remain
13949          tag = audioTags.shift();
13950        } else if (!audioTags.length) {
13951          // only video tags remain
13952          tag = videoTags.shift();
13953        } else if (audioTags[0].dts < videoTags[0].dts) {
13954          // audio should be decoded next
13955          tag = audioTags.shift();
13956        } else {
13957          // video should be decoded next
13958          tag = videoTags.shift();
13959        }
13960
13961        tags.push(tag.finalize());
13962      }
13963
13964      return tags;
13965    }
13966  }]);
13967
13968  return FlashSourceBuffer;
13969})(_videoJs2['default'].EventTarget);
13970
13971exports['default'] = FlashSourceBuffer;
13972module.exports = exports['default'];
13973}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
13974},{"./add-text-track-data":84,"./create-text-tracks-if-necessary":86,"./flash-constants":87,"./remove-cues-from-track":91,"global/window":25,"mux.js/lib/flv":71}],90:[function(require,module,exports){
13975(function (global){
13976/**
13977 * @file html-media-source.js
13978 */
13979'use strict';
13980
13981Object.defineProperty(exports, '__esModule', {
13982  value: true
13983});
13984
13985var _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; }; })();
13986
13987var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
13988
13989function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
13990
13991function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
13992
13993function _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, { c
13993onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
13994
13995var _globalWindow = require('global/window');
13996
13997var _globalWindow2 = _interopRequireDefault(_globalWindow);
13998
13999var _globalDocument = require('global/document');
14000
14001var _globalDocument2 = _interopRequireDefault(_globalDocument);
14002
14003var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
14004
14005var _videoJs2 = _interopRequireDefault(_videoJs);
14006
14007var _virtualSourceBuffer = require('./virtual-source-buffer');
14008
14009var _virtualSourceBuffer2 = _interopRequireDefault(_virtualSourceBuffer);
14010
14011var _addTextTrackData = require('./add-text-track-data');
14012
14013var _codecUtils = require('./codec-utils');
14014
14015/**
14016 * Replace the old apple-style `avc1.<dd>.<dd>` codec string with the standard
14017 * `avc1.<hhhhhh>`
14018 *
14019 * @param {Array} codecs an array of codec strings to fix
14020 * @return {Array} the translated codec array
14021 * @private
14022 */
14023var translateLegacyCodecs = function translateLegacyCodecs(codecs) {
14024  return codecs.map(function (codec) {
14025    return codec.replace(/avc1\.(\d+)\.(\d+)/i, function (orig, profile, avcLevel) {
14026      var profileHex = ('00' + Number(profile).toString(16)).slice(-2);
14027      var avcLevelHex = ('00' + Number(avcLevel).toString(16)).slice(-2);
14028
14029      return 'avc1.' + profileHex + '00' + avcLevelHex;
14030    });
14031  });
14032};
14033
14034/**
14035 * Our MediaSource implementation in HTML, mimics native
14036 * MediaSource where/if possible.
14037 *
14038 * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
14039 * @class HtmlMediaSource
14040 * @extends videojs.EventTarget
14041 */
14042
14043var HtmlMediaSource = (function (_videojs$EventTarget) {
14044  _inherits(HtmlMediaSource, _videojs$EventTarget);
14045
14046  function HtmlMediaSource() {
14047    var _this = this;
14048
14049    _classCallCheck(this, HtmlMediaSource);
14050
14051    _get(Object.getPrototypeOf(HtmlMediaSource.prototype), 'constructor', this).call(this);
14052    var property = undefined;
14053
14054    this.nativeMediaSource_ = new _globalWindow2['default'].MediaSource();
14055    // delegate to the native MediaSource's methods by default
14056    for (property in this.nativeMediaSource_) {
14057      if (!(property in HtmlMediaSource.prototype) && typeof this.nativeMediaSource_[property] === 'function') {
14058        this[property] = this.nativeMediaSource_[property].bind(this.nativeMediaSource_);
14059      }
14060    }
14061
14062    // emulate `duration` and `seekable` until seeking can be
14063    // handled uniformly for live streams
14064    // see https://github.com/w3c/media-source/issues/5
14065    this.duration_ = NaN;
14066    Object.defineProperty(this, 'duration', {
14067      get: function get() {
14068        if (this.duration_ === Infinity) {
14069          return this.duration_;
14070        }
14071        return this.nativeMediaSource_.duration;
14072      },
14073      set: function set(duration) {
14074        this.duration_ = duration;
14075        if (duration !== Infinity) {
14076          this.nativeMediaSource_.duration = duration;
14077          return;
14078        }
14079      }
14080    });
14081    Object.defineProperty(this, 'seekable', {
14082      get: function get() {
14083        if (this.duration_ === Infinity) {
14084          return _videoJs2['default'].createTimeRanges([[0, this.nativeMediaSource_.duration]]);
14085        }
14086        return this.nativeMediaSource_.seekable;
14087      }
14088    });
14089
14090    Object.defineProperty(this, 'readyState', {
14091      get: function get() {
14092        return this.nativeMediaSource_.readyState;
14093      }
14094    });
14095
14096    Object.defineProperty(this, 'activeSourceBuffers', {
14097      get: function get() {
14098        return this.activeSourceBuffers_;
14099      }
14100    });
14101
14102    // the list of virtual and native SourceBuffers created by this
14103    // MediaSource
14104    this.sourceBuffers = [];
14105
14106    this.activeSourceBuffers_ = [];
14107
14108    /**
14109     * update the list of active source buffers based upon various
14110     * imformation from HLS and video.js
14111     *
14112     * @private
14113     */
14114    this.updateActiveSourceBuffers_ = function () {
14115      // Retain the reference but empty the array
14116      _this.activeSourceBuffers_.length = 0;
14117
14118      // By default, the audio in the combined virtual source buffer is enabled
14119      // and the audio-only source buffer (if it exists) is disabled.
14120      var combined = false;
14121      var audioOnly = true;
14122
14123      // TODO: maybe we can store the sourcebuffers on the track objects?
14124      // safari may do something like this
14125      for (var i = 0; i < _this.player_.audioTracks().length; i++) {
14126        var track = _this.player_.audioTracks()[i];
14127
14128        if (track.enabled && track.kind !== 'main') {
14129          // The enabled track is an alternate audio track so disable the audio in
14130          // the combined source buffer and enable the audio-only source buffer.
14131          combined = true;
14132          audioOnly = false;
14133          break;
14134        }
14135      }
14136
14137      // Since we currently support a max of two source buffers, add all of the source
14138      // buffers (in order).
14139      _this.sourceBuffers.forEach(function (sourceBuffer) {
14140        /* eslinst-disable */
14141        // TODO once codecs are required, we can switch to using the codecs to determine
14142        //      what stream is the video stream, rather than relying on videoTracks
14143        /* eslinst-enable */
14144
14145        sourceBuffer.appendAudioInitSegment_ = true;
14146
14147        if (sourceBuffer.videoCodec_ && sourceBuffer.audioCodec_) {
14148          // combined
14149          sourceBuffer.audioDisabled_ = combined;
14150        } else if (sourceBuffer.videoCodec_ && !sourceBuffer.audioCodec_) {
14151          // If the "combined" source buffer is video only, then we do not want
14152          // disable the audio-only source buffer (this is mostly for demuxed
14153          // audio and video hls)
14154          sourceBuffer.audioDisabled_ = true;
14155          audioOnly = false;
14156        } else if (!sourceBuffer.videoCodec_ && sourceBuffer.audioCodec_) {
14157          // audio only
14158          sourceBuffer.audioDisabled_ = audioOnly;
14159          if (audioOnly) {
14160            return;
14161          }
14162        }
14163
14164        _this.activeSourceBuffers_.push(sourceBuffer);
14165      });
14166    };
14167
14168    this.onPlayerMediachange_ = function () {
14169      _this.sourceBuffers.forEach(function (sourceBuffer) {
14170        sourceBuffer.appendAudioInitSegment_ = true;
14171      });
14172    };
14173
14174    // Re-emit MediaSource events on the polyfill
14175    ['sourceopen', 'sourceclose', 'sourceended'].forEach(function (eventName) {
14176      this.nativeMediaSource_.addEventListener(eventName, this.trigger.bind(this));
14177    }, this);
14178
14179    // capture the associated player when the MediaSource is
14180    // successfully attached
14181    this.on('sourceopen', function (event) {
14182      // Get the player this MediaSource is attached to
14183      var video = _globalDocument2['default'].querySelector('[src="' + _this.url_ + '"]');
14184
14185      if (!video) {
14186        return;
14187      }
14188
14189      _this.player_ = (0, _videoJs2['default'])(video.parentNode);
14190
14191      if (_this.player_.audioTracks && _this.player_.audioTracks()) {
14192        _this.player_.audioTracks().on('change', _this.updateActiveSourceBuffers_);
14193        _this.player_.audioTracks().on('addtrack', _this.updateActiveSourceBuffers_);
14194        _this.player_.audioTracks().on('removetrack', _this.updateActiveSourceBuffers_);
14195      }
14196
14197      _this.player_.on('mediachange', _this.onPlayerMediachange_);
14198    });
14199
14200    this.on('sourceended', function (event) {
14201      var duration = (0, _addTextTrackData.durationOfVideo)(_this.duration);
14202
14203      for (var i = 0; i < _this.sourceBuffers.length; i++) {
14204        var sourcebuffer = _this.sourceBuffers[i];
14205        var cues = sourcebuffer.metadataTrack_ && sourcebuffer.metadataTrack_.cues;
14206
14207        if (cues && cues.length) {
14208          cues[cues.length - 1].endTime = duration;
14209        }
14210      }
14211    });
14212
14213    // explicitly terminate any WebWorkers that were created
14214    // by SourceHandlers
14215    this.on('sourceclose', function (event) {
14216      this.sourceBuffers.forEach(function (sourceBuffer) {
14217        if (sourceBuffer.transmuxer_) {
14218          sourceBuffer.transmuxer_.terminate();
14219        }
14220      });
14221      this.sourceBuffers.length = 0;
14222      if (!this.player_) {
14223        return;
14224      }
14225
14226      if (this.player_.audioTracks && this.player_.audioTracks()) {
14227        this.player_.audioTracks().off('change', this.updateActiveSourceBuffers_);
14228        this.player_.audioTracks().off('addtrack', this.updateActiveSourceBuffers_);
14229        this.player_.audioTracks().off('removetrack', this.updateActiveSourceBuffers_);
14230      }
14231
14232      this.player_.off('mediachange', this.onPlayerMediachange_);
14233    });
14234  }
14235
14236  /**
14237   * Add a range that that can now be seeked to.
14238   *
14239   * @param {Double} start where to start the addition
14240   * @param {Double} end where to end the addition
14241   * @private
14242   */
14243
14244  _createClass(HtmlMediaSource, [{
14245    key: 'addSeekableRange_',
14246    value: function addSeekableRange_(start, end) {
14247      var error = undefined;
14248
14249      if (this.duration !== Infinity) {
14250        error = new Error('MediaSource.addSeekableRange() can only be invoked ' + 'when the duration is Infinity');
14251        error.name = 'InvalidStateError';
14252        error.code = 11;
14253        throw error;
14254      }
14255
14256      if (end > this.nativeMediaSource_.duration || isNaN(this.nativeMediaSource_.duration)) {
14257        this.nativeMediaSource_.duration = end;
14258      }
14259    }
14260
14261    /**
14262     * Add a source buffer to the media source.
14263     *
14264     * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/addSourceBuffer
14265     * @param {String} type the content-type of the content
14266     * @return {Object} the created source buffer
14267     */
14268  }, {
14269    key: 'addSourceBuffer',
14270    value: function addSourceBuffer(type) {
14271      var buffer = undefined;
14272      var parsedType = (0, _codecUtils.parseContentType)(type);
14273
14274      // Create a VirtualSourceBuffer to transmux MPEG-2 transport
14275      // stream segments into fragmented MP4s
14276      if (/^(video|audio)\/mp2t$/i.test(parsedType.type)) {
14277        var codecs = [];
14278
14279        if (parsedType.parameters && parsedType.parameters.codecs) {
14280          codecs = parsedType.parameters.codecs.split(',');
14281          codecs = translateLegacyCodecs(codecs);
14282          codecs = codecs.filter(function (codec) {
14283            return (0, _codecUtils.isAudioCodec)(codec) || (0, _codecUtils.isVideoCodec)(codec);
14284          });
14285        }
14286
14287        if (codecs.length === 0) {
14288          codecs = ['avc1.4d400d', 'mp4a.40.2'];
14289        }
14290
14291        buffer = new _virtualSourceBuffer2['default'](this, codecs);
14292
14293        if (this.sourceBuffers.length !== 0) {
14294          // If another VirtualSourceBuffer already exists, then we are creating a
14295          // SourceBuffer for an alternate audio track and therefore we know that
14296          // the source has both an audio and video track.
14297          // That means we should trigger the manual creation of the real
14298          // SourceBuffers instead of waiting for the transmuxer to return data
14299          this.sourceBuffers[0].createRealSourceBuffers_();
14300          buffer.createRealSourceBuffers_();
14301
14302          // Automatically disable the audio on the first source buffer if
14303          // a second source buffer is ever created
14304          this.sourceBuffers[0].audioDisabled_ = true;
14305        }
14306      } else {
14307        // delegate to the native implementation
14308        buffer = this.nativeMediaSource_.addSourceBuffer(type);
14309      }
14310
14311      this.sourceBuffers.push(buffer);
14312      return buffer;
14313    }
14314  }]);
14315
14316  return HtmlMediaSource;
14317})(_videoJs2['default'].EventTarget);
14318
14319exports['default'] = HtmlMediaSource;
14320module.exports = exports['default'];
14321}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
14322},{"./add-text-track-data":84,"./codec-utils":85,"./virtual-source-buffer":94,"global/document":24,"global/window":25}],91:[function(require,module,exports){
14323/**
14324 * @file remove-cues-from-track.js
14325 */
14326
14327/**
14328 * Remove cues from a track on video.js.
14329 *
14330 * @param {Double} start start of where we should remove the cue
14331 * @param {Double} end end of where the we should remove the cue
14332 * @param {Object} track the text track to remove the cues from
14333 * @private
14334 */
14335"use strict";
14336
14337Object.defineProperty(exports, "__esModule", {
14338  value: true
14339});
14340var removeCuesFromTrack = function removeCuesFromTrack(start, end, track) {
14341  var i = undefined;
14342  var cue = undefined;
14343
14344  if (!track) {
14345    return;
14346  }
14347
14348  i = track.cues.length;
14349
14350  while (i--) {
14351    cue = track.cues[i];
14352
14353    // Remove any overlapping cue
14354    if (cue.startTime <= end && cue.endTime >= start) {
14355      track.removeCue(cue);
14356    }
14357  }
14358};
14359
14360exports["default"] = removeCuesFromTrack;
14361module.exports = exports["default"];
14362},{}],92:[function(require,module,exports){
14363/**
14364 * @file transmuxer-worker.js
14365 */
14366
14367/**
14368 * videojs-contrib-media-sources
14369 *
14370 * Copyright (c) 2015 Brightcove
14371 * All rights reserved.
14372 *
14373 * Handles communication between the browser-world and the mux.js
14374 * transmuxer running inside of a WebWorker by exposing a simple
14375 * message-based interface to a Transmuxer object.
14376 */
14377'use strict';
14378
14379Object.defineProperty(exports, '__esModule', {
14380  value: true
14381});
14382
14383var _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; }; })();
14384
14385function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14386
14387function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
14388
14389var _globalWindow = require('global/window');
14390
14391var _globalWindow2 = _interopRequireDefault(_globalWindow);
14392
14393var _muxJsLibMp4 = require('mux.js/lib/mp4');
14394
14395var _muxJsLibMp42 = _interopRequireDefault(_muxJsLibMp4);
14396
14397/**
14398 * Re-emits tranmsuxer events by converting them into messages to the
14399 * world outside the worker.
14400 *
14401 * @param {Object} transmuxer the transmuxer to wire events on
14402 * @private
14403 */
14404var wireTransmuxerEvents = function wireTransmuxerEvents(transmuxer) {
14405  transmuxer.on('data', function (segment) {
14406    // transfer ownership of the underlying ArrayBuffer
14407    // instead of doing a copy to save memory
14408    // ArrayBuffers are transferable but generic TypedArrays are not
14409    // @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects)
14410    var initArray = segment.initSegment;
14411
14412    segment.initSegment = {
14413      data: initArray.buffer,
14414      byteOffset: initArray.byteOffset,
14415      byteLength: initArray.byteLength
14416    };
14417
14418    var typedArray = segment.data;
14419
14420    segment.data = typedArray.buffer;
14421    _globalWindow2['default'].postMessage({
14422      action: 'data',
14423      segment: segment,
14424      byteOffset: typedArray.byteOffset,
14425      byteLength: typedArray.byteLength
14426    }, [segment.data]);
14427  });
14428
14429  if (transmuxer.captionStream) {
14430    transmuxer.captionStream.on('data', function (caption) {
14431      _globalWindow2['default'].postMessage({
14432        action: 'caption',
14433        data: caption
14434      });
14435    });
14436  }
14437
14438  transmuxer.on('done', function (data) {
14439    _globalWindow2['default'].postMessage({ action: 'done' });
14440  });
14441};
14442
14443/**
14444 * All incoming messages route through this hash. If no function exists
14445 * to handle an incoming message, then we ignore the message.
14446 *
14447 * @class MessageHandlers
14448 * @param {Object} options the options to initialize with
14449 */
14450
14451var MessageHandlers = (function () {
14452  function MessageHandlers(options) {
14453    _classCallCheck(this, MessageHandlers);
14454
14455    this.options = options || {};
14456    this.init();
14457  }
14458
14459  /**
14460   * Our web wroker interface so that things can talk to mux.js
14461   * that will be running in a web worker. the scope is passed to this by
14462   * webworkify.
14463   *
14464   * @param {Object} self the scope for the web worker
14465   */
14466
14467  /**
14468   * initialize our web worker and wire all the events.
14469   */
14470
14471  _createClass(MessageHandlers, [{
14472    key: 'init',
14473    value: function init() {
14474      if (this.transmuxer) {
14475        this.transmuxer.dispose();
14476      }
14477      this.transmuxer = new _muxJsLibMp42['default'].Transmuxer(this.options);
14478      wireTransmuxerEvents(this.transmuxer);
14479    }
14480
14481    /**
14482     * Adds data (a ts segment) to the start of the transmuxer pipeline for
14483     * processing.
14484     *
14485     * @param {ArrayBuffer} data data to push into the muxer
14486     */
14487  }, {
14488    key: 'push',
14489    value: function push(data) {
14490      // Cast array buffer to correct type for transmuxer
14491      var segment = new Uint8Array(data.data, data.byteOffset, data.byteLength);
14492
14493      this.transmuxer.push(segment);
14494    }
14495
14496    /**
14497     * Recreate the transmuxer so that the next segment added via `push`
14498     * start with a fresh transmuxer.
14499     */
14500  }, {
14501    key: 'reset',
14502    value: function reset() {
14503      this.init();
14504    }
14505
14506    /**
14507     * Set the value that will be used as the `baseMediaDecodeTime` time for the
14508     * next segment pushed in. Subsequent segments will have their `baseMediaDecodeTime`
14509     * set relative to the first based on the PTS values.
14510     *
14511     * @param {Object} data used to set the timestamp offset in the muxer
14512     */
14513  }, {
14514    key: 'setTimestampOffset',
14515    value: function setTimestampOffset(data) {
14516      var timestampOffset = data.timestampOffset || 0;
14517
14518      this.transmuxer.setBaseMediaDecodeTime(Math.round(timestampOffset * 90000));
14519    }
14520
14521    /**
14522     * Forces the pipeline to finish processing the last segment and emit it's
14523     * results.
14524     *
14525     * @param {Object} data event data, not really used
14526     */
14527  }, {
14528    key: 'flush',
14529    value: function flush(data) {
14530      this.transmuxer.flush();
14531    }
14532  }]);
14533
14534  return MessageHandlers;
14535})();
14536
14537var Worker = function Worker(self) {
14538  self.onmessage = function (event) {
14539    if (event.data.action === 'init' && event.data.options) {
14540      this.messageHandlers = new MessageHandlers(event.data.options);
14541      return;
14542    }
14543
14544    if (!this.messageHandlers) {
14545      this.messageHandlers = new MessageHandlers();
14546    }
14547
14548    if (event.data && event.data.action && event.data.action !== 'init') {
14549      if (this.messageHandlers[event.data.action]) {
14550        this.messageHandlers[event.data.action](event.data);
14551      }
14552    }
14553  };
14554};
14555
14556exports['default'] = function (self) {
14557  return new Worker(self);
14558};
14559
14560module.exports = exports['default'];
14561},{"global/window":25,"mux.js/lib/mp4":78}],93:[function(require,module,exports){
14562(function (global){
14563/**
14564 * @file videojs-contrib-media-sources.js
14565 */
14566'use strict';
14567
14568Object.defineProperty(exports, '__esModule', {
14569  value: true
14570});
14571
14572function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14573
14574var _globalWindow = require('global/window');
14575
14576var _globalWindow2 = _interopRequireDefault(_globalWindow);
14577
14578var _flashMediaSource = require('./flash-media-source');
14579
14580var _flashMediaSource2 = _interopRequireDefault(_flashMediaSource);
14581
14582var _htmlMediaSource = require('./html-media-source');
14583
14584var _htmlMediaSource2 = _interopRequireDefault(_htmlMediaSource);
14585
14586var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
14587
14588var _videoJs2 = _interopRequireDefault(_videoJs);
14589
14590var urlCount = 0;
14591
14592// ------------
14593// Media Source
14594// ------------
14595
14596var defaults = {
14597  // how to determine the MediaSource implementation to use. There
14598  // are three available modes:
14599  // - auto: use native MediaSources where available and Flash
14600  //   everywhere else
14601  // - html5: always use native MediaSources
14602  // - flash: always use the Flash MediaSource polyfill
14603  mode: 'auto'
14604};
14605
14606// store references to the media sources so they can be connected
14607// to a video element (a swf object)
14608// TODO: can we store this somewhere local to this module?
14609_videoJs2['default'].mediaSources = {};
14610
14611/**
14612 * Provide a method for a swf object to notify JS that a
14613 * media source is now open.
14614 *
14615 * @param {String} msObjectURL string referencing the MSE Object URL
14616 * @param {String} swfId the swf id
14617 */
14618var open = function open(msObjectURL, swfId) {
14619  var mediaSource = _videoJs2['default'].mediaSources[msObjectURL];
14620
14621  if (mediaSource) {
14622    mediaSource.trigger({ type: 'sourceopen', swfId: swfId });
14623  } else {
14624    throw new Error('Media Source not found (Video.js)');
14625  }
14626};
14627
14628/**
14629 * Check to see if the native MediaSource object exists and supports
14630 * an MP4 container with both H.264 video and AAC-LC audio.
14631 *
14632 * @return {Boolean} if  native media sources are supported
14633 */
14634var supportsNativeMediaSources = function supportsNativeMediaSources() {
14635  return !!_globalWindow2['default'].MediaSource && !!_globalWindow2['default'].MediaSource.isTypeSupported && _globalWindow2['default'].MediaSource.isTypeSupported('video/mp4;codecs="avc1.4d400d,mp4a.40.2"');
14636};
14637
14638/**
14639 * An emulation of the MediaSource API so that we can support
14640 * native and non-native functionality such as flash and
14641 * video/mp2t videos. returns an instance of HtmlMediaSource or
14642 * FlashMediaSource depending on what is supported and what options
14643 * are passed in.
14644 *
14645 * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/MediaSource
14646 * @param {Object} options options to use during setup.
14647 */
14648var MediaSource = function MediaSource(options) {
14649  var settings = _videoJs2['default'].mergeOptions(defaults, options);
14650
14651  this.MediaSource = {
14652    open: open,
14653    supportsNativeMediaSources: supportsNativeMediaSources
14654  };
14655
14656  // determine whether HTML MediaSources should be used
14657  if (settings.mode === 'html5' || settings.mode === 'auto' && supportsNativeMediaSources()) {
14658    return new _htmlMediaSource2['default']();
14659  }
14660
14661  // otherwise, emulate them through the SWF
14662  return new _flashMediaSource2['default']();
14663};
14664
14665exports.MediaSource = MediaSource;
14666MediaSource.open = open;
14667MediaSource.supportsNativeMediaSources = supportsNativeMediaSources;
14668
14669/**
14670 * A wrapper around the native URL for our MSE object
14671 * implementation, this object is exposed under videojs.URL
14672 *
14673 * @link https://developer.mozilla.org/en-US/docs/Web/API/URL/URL
14674 */
14675var URL = {
14676  /**
14677   * A wrapper around the native createObjectURL for our objects.
14678   * This function maps a native or emulated mediaSource to a blob
14679   * url so that it can be loaded into video.js
14680   *
14681   * @link https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
14682   * @param {MediaSource} object the object to create a blob url to
14683   */
14684  createObjectURL: function createObjectURL(object) {
14685    var objectUrlPrefix = 'blob:vjs-media-source/';
14686    var url = undefined;
14687
14688    // use the native MediaSource to generate an object URL
14689    if (object instanceof _htmlMediaSource2['default']) {
14690      url = _globalWindow2['default'].URL.createObjectURL(object.nativeMediaSource_);
14691      object.url_ = url;
14692      return url;
14693    }
14694    // if the object isn't an emulated MediaSource, delegate to the
14695    // native implementation
14696    if (!(object instanceof _flashMediaSource2['default'])) {
14697      url = _globalWindow2['default'].URL.createObjectURL(object);
14698      object.url_ = url;
14699      return url;
14700    }
14701
14702    // build a URL that can be used to map back to the emulated
14703    // MediaSource
14704    url = objectUrlPrefix + urlCount;
14705
14706    urlCount++;
14707
14708    // setup the mapping back to object
14709    _videoJs2['default'].mediaSources[url] = object;
14710
14711    return url;
14712  }
14713};
14714
14715exports.URL = URL;
14716_videoJs2['default'].MediaSource = MediaSource;
14717_videoJs2['default'].URL = URL;
14718}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
14719},{"./flash-media-source":88,"./html-media-source":90,"global/window":25}],94:[function(require,module,exports){
14720(function (global){
14721/**
14722 * @file virtual-source-buffer.js
14723 */
14724'use strict';
14725
14726Object.defineProperty(exports, '__esModule', {
14727  value: true
14728});
14729
14730var _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; }; })();
14731
14732var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
14733
14734function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14735
14736function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
14737
14738function _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, { c
14738onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
14739
14740var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
14741
14742var _videoJs2 = _interopRequireDefault(_videoJs);
14743
14744var _createTextTracksIfNecessary = require('./create-text-tracks-if-necessary');
14745
14746var _createTextTracksIfNecessary2 = _interopRequireDefault(_createTextTracksIfNecessary);
14747
14748var _removeCuesFromTrack = require('./remove-cues-from-track');
14749
14750var _removeCuesFromTrack2 = _interopRequireDefault(_removeCuesFromTrack);
14751
14752var _addTextTrackData = require('./add-text-track-data');
14753
14754var _webworkify = require('webworkify');
14755
14756var _webworkify2 = _interopRequireDefault(_webworkify);
14757
14758var _transmuxerWorker = require('./transmuxer-worker');
14759
14760var _transmuxerWorker2 = _interopRequireDefault(_transmuxerWorker);
14761
14762var _codecUtils = require('./codec-utils');
14763
14764/**
14765 * VirtualSourceBuffers exist so that we can transmux non native formats
14766 * into a native format, but keep the same api as a native source buffer.
14767 * It creates a transmuxer, that works in its own thread (a web worker) and
14768 * that transmuxer muxes the data into a native format. VirtualSourceBuffer will
14769 * then send all of that data to the naive sourcebuffer so that it is
14770 * indestinguishable from a natively supported format.
14771 *
14772 * @param {HtmlMediaSource} mediaSource the parent mediaSource
14773 * @param {Array} codecs array of codecs that we will be dealing with
14774 * @class VirtualSourceBuffer
14775 * @extends video.js.EventTarget
14776 */
14777
14778var VirtualSourceBuffer = (function (_videojs$EventTarget) {
14779  _inherits(VirtualSourceBuffer, _videojs$EventTarget);
14780
14781  function VirtualSourceBuffer(mediaSource, codecs) {
14782    var _this = this;
14783
14784    _classCallCheck(this, VirtualSourceBuffer);
14785
14786    _get(Object.getPrototypeOf(VirtualSourceBuffer.prototype), 'constructor', this).call(this, _videoJs2['default'].EventTarget);
14787    this.timestampOffset_ = 0;
14788    this.pendingBuffers_ = [];
14789    this.bufferUpdating_ = false;
14790    this.mediaSource_ = mediaSource;
14791    this.codecs_ = codecs;
14792    this.audioCodec_ = null;
14793    this.videoCodec_ = null;
14794    this.audioDisabled_ = false;
14795    this.appendAudioInitSegment_ = true;
14796
14797    var options = {
14798      remux: false
14799    };
14800
14801    this.codecs_.forEach(function (codec) {
14802      if ((0, _codecUtils.isAudioCodec)(codec)) {
14803        _this.audioCodec_ = codec;
14804      } else if ((0, _codecUtils.isVideoCodec)(codec)) {
14805        _this.videoCodec_ = codec;
14806      }
14807    });
14808
14809    // append muxed segments to their respective native buffers as
14810    // soon as they are available
14811    this.transmuxer_ = (0, _webworkify2['default'])(_transmuxerWorker2['default']);
14812    this.transmuxer_.postMessage({ action: 'init', options: options });
14813
14814    this.transmuxer_.onmessage = function (event) {
14815      if (event.data.action === 'data') {
14816        return _this.data_(event);
14817      }
14818
14819      if (event.data.action === 'done') {
14820        return _this.done_(event);
14821      }
14822    };
14823
14824    // this timestampOffset is a property with the side-effect of resetting
14825    // baseMediaDecodeTime in the transmuxer on the setter
14826    Object.defineProperty(this, 'timestampOffset', {
14827      get: function get() {
14828        return this.timestampOffset_;
14829      },
14830      set: function set(val) {
14831        if (typeof val === 'number' && val >= 0) {
14832          this.timestampOffset_ = val;
14833          this.appendAudioInitSegment_ = true;
14834
14835          // We have to tell the transmuxer to set the baseMediaDecodeTime to
14836          // the desired timestampOffset for the next segment
14837          this.transmuxer_.postMessage({
14838            action: 'setTimestampOffset',
14839            timestampOffset: val
14840          });
14841        }
14842      }
14843    });
14844
14845    // setting the append window affects both source buffers
14846    Object.defineProperty(this, 'appendWindowStart', {
14847      get: function get() {
14848        return (this.videoBuffer_ || this.audioBuffer_).appendWindowStart;
14849      },
14850      set: function set(start) {
14851        if (this.videoBuffer_) {
14852          this.videoBuffer_.appendWindowStart = start;
14853        }
14854        if (this.audioBuffer_) {
14855          this.audioBuffer_.appendWindowStart = start;
14856        }
14857      }
14858    });
14859
14860    // this buffer is "updating" if either of its native buffers are
14861    Object.defineProperty(this, 'updating', {
14862      get: function get() {
14863        return !!(this.bufferUpdating_ || !this.audioDisabled_ && this.audioBuffer_ && this.audioBuffer_.updating || this.videoBuffer_ && this.videoBuffer_.updating);
14864      }
14865    });
14866
14867    // the buffered property is the intersection of the buffered
14868    // ranges of the native source buffers
14869    Object.defineProperty(this, 'buffered', {
14870      get: function get() {
14871        var start = null;
14872        var end = null;
14873        var arity = 0;
14874        var extents = [];
14875        var ranges = [];
14876
14877        // neither buffer has been created yet
14878        if (!this.videoBuffer_ && !this.audioBuffer_) {
14879          return _videoJs2['default'].createTimeRange();
14880        }
14881
14882        // only one buffer is configured
14883        if (!this.videoBuffer_) {
14884          return this.audioBuffer_.buffered;
14885        }
14886        if (!this.audioBuffer_) {
14887          return this.videoBuffer_.buffered;
14888        }
14889
14890        // both buffers are configured
14891        if (this.audioDisabled_) {
14892          return this.videoBuffer_.buffered;
14893        }
14894
14895        // both buffers are empty
14896        if (this.videoBuffer_.buffered.length === 0 && this.audioBuffer_.buffered.length === 0) {
14897          return _videoJs2['default'].createTimeRange();
14898        }
14899
14900        // Handle the case where we have both buffers and create an
14901        // intersection of the two
14902        var videoBuffered = this.videoBuffer_.buffered;
14903        var audioBuffered = this.audioBuffer_.buffered;
14904        var count = videoBuffered.length;
14905
14906        // A) Gather up all start and end times
14907        while (count--) {
14908          extents.push({ time: videoBuffered.start(count), type: 'start' });
14909          extents.push({ time: videoBuffered.end(count), type: 'end' });
14910        }
14911        count = audioBuffered.length;
14912        while (count--) {
14913          extents.push({ time: audioBuffered.start(count), type: 'start' });
14914          extents.push({ time: audioBuffered.end(count), type: 'end' });
14915        }
14916        // B) Sort them by time
14917        extents.sort(function (a, b) {
14918          return a.time - b.time;
14919        });
14920
14921        // C) Go along one by one incrementing arity for start and decrementing
14922        //    arity for ends
14923        for (count = 0; count < extents.length; count++) {
14924          if (extents[count].type === 'start') {
14925            arity++;
14926
14927            // D) If arity is ever incremented to 2 we are entering an
14928            //    overlapping range
14929            if (arity === 2) {
14930              start = extents[count].time;
14931            }
14932          } else if (extents[count].type === 'end') {
14933            arity--;
14934
14935            // E) If arity is ever decremented to 1 we leaving an
14936            //    overlapping range
14937            if (arity === 1) {
14938              end = extents[count].time;
14939            }
14940          }
14941
14942          // F) Record overlapping ranges
14943          if (start !== null && end !== null) {
14944            ranges.push([start, end]);
14945            start = null;
14946            end = null;
14947          }
14948        }
14949
14950        return _videoJs2['default'].createTimeRanges(ranges);
14951      }
14952    });
14953  }
14954
14955  /**
14956   * When we get a data event from the transmuxer
14957   * we call this function and handle the data that
14958   * was sent to us
14959   *
14960   * @private
14961   * @param {Event} event the data event from the transmuxer
14962   */
14963
14964  _createClass(VirtualSourceBuffer, [{
14965    key: 'data_',
14966    value: function data_(event) {
14967      var segment = event.data.segment;
14968
14969      // Cast ArrayBuffer to TypedArray
14970      segment.data = new Uint8Array(segment.data, event.data.byteOffset, event.data.byteLength);
14971
14972      segment.initSegment = new Uint8Array(segment.initSegment.data, segment.initSegment.byteOffset, segment.initSegment.byteLength);
14973
14974      (0, _createTextTracksIfNecessary2['default'])(this, this.mediaSource_, segment);
14975
14976      // Add the segments to the pendingBuffers array
14977      this.pendingBuffers_.push(segment);
14978      return;
14979    }
14980
14981    /**
14982     * When we get a done event from the transmuxer
14983     * we call this function and we process all
14984     * of the pending data that we have been saving in the
14985     * data_ function
14986     *
14987     * @private
14988     * @param {Event} event the done event from the transmuxer
14989     */
14990  }, {
14991    key: 'done_',
14992    value: function done_(event) {
14993      // All buffers should have been flushed from the muxer
14994      // start processing anything we have received
14995      this.processPendingSegments_();
14996      return;
14997    }
14998
14999    /**
15000     * Create our internal native audio/video source buffers and add
15001     * event handlers to them with the following conditions:
15002     * 1. they do not already exist on the mediaSource
15003     * 2. this VSB has a codec for them
15004     *
15005     * @private
15006     */
15007  }, {
15008    key: 'createRealSourceBuffers_',
15009    value: function createRealSourceBuffers_() {
15010      var _this2 = this;
15011
15012      var types = ['audio', 'video'];
15013
15014      types.forEach(function (type) {
15015        // Don't create a SourceBuffer of this type if we don't have a
15016        // codec for it
15017        if (!_this2[type + 'Codec_']) {
15018          return;
15019        }
15020
15021        // Do nothing if a SourceBuffer of this type already exists
15022        if (_this2[type + 'Buffer_']) {
15023          return;
15024        }
15025
15026        var buffer = null;
15027
15028        // If the mediasource already has a SourceBuffer for the codec
15029        // use that
15030        if (_this2.mediaSource_[type + 'Buffer_']) {
15031          buffer = _this2.mediaSource_[type + 'Buffer_'];
15032        } else {
15033          buffer = _this2.mediaSource_.nativeMediaSource_.addSourceBuffer(type + '/mp4;codecs="' + _this2[type + 'Codec_'] + '"');
15034          _this2.mediaSource_[type + 'Buffer_'] = buffer;
15035        }
15036
15037        _this2[type + 'Buffer_'] = buffer;
15038
15039        // Wire up the events to the SourceBuffer
15040        ['update', 'updatestart', 'updateend'].forEach(function (event) {
15041          buffer.addEventListener(event, function () {
15042            // if audio is disabled
15043            if (type === 'audio' && _this2.audioDisabled_) {
15044              return;
15045            }
15046
15047            var shouldTrigger = types.every(function (t) {
15048              // skip checking audio's updating status if audio
15049              // is not enabled
15050              if (t === 'audio' && _this2.audioDisabled_) {
15051                return true;
15052              }
15053              // if the other type if updating we don't trigger
15054              if (type !== t && _this2[t + 'Buffer_'] && _this2[t + 'Buffer_'].updating) {
15055                return false;
15056              }
15057              return true;
15058            });
15059
15060            if (shouldTrigger) {
15061              return _this2.trigger(event);
15062            }
15063          });
15064        });
15065      });
15066    }
15067
15068    /**
15069     * Emulate the native mediasource function, but our function will
15070     * send all of the proposed segments to the transmuxer so that we
15071     * can transmux them before we append them to our internal
15072     * native source buffers in the correct format.
15073     *
15074     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/appendBuffer
15075     * @param {Uint8Array} segment the segment to append to the buffer
15076     */
15077  }, {
15078    key: 'appendBuffer',
15079    value: function appendBuffer(segment) {
15080      // Start the internal "updating" state
15081      this.bufferUpdating_ = true;
15082
15083      this.transmuxer_.postMessage({
15084        action: 'push',
15085        // Send the typed-array of data as an ArrayBuffer so that
15086        // it can be sent as a "Transferable" and avoid the costly
15087        // memory copy
15088        data: segment.buffer,
15089
15090        // To recreate the original typed-array, we need information
15091        // about what portion of the ArrayBuffer it was a view into
15092        byteOffset: segment.byteOffset,
15093        byteLength: segment.byteLength
15094      }, [segment.buffer]);
15095      this.transmuxer_.postMessage({ action: 'flush' });
15096    }
15097
15098    /**
15099     * Emulate the native mediasource function and remove parts
15100     * of the buffer from any of our internal buffers that exist
15101     *
15102     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/remove
15103     * @param {Double} start position to start the remove at
15104     * @param {Double} end position to end the remove at
15105     */
15106  }, {
15107    key: 'remove',
15108    value: function remove(start, end) {
15109      if (this.videoBuffer_) {
15110        this.videoBuffer_.remove(start, end);
15111      }
15112      if (this.audioBuffer_) {
15113        this.audioBuffer_.remove(start, end);
15114      }
15115
15116      // Remove Metadata Cues (id3)
15117      (0, _removeCuesFromTrack2['default'])(start, end, this.metadataTrack_);
15118
15119      // Remove Any Captions
15120      (0, _removeCuesFromTrack2['default'])(start, end, this.inbandTextTrack_);
15121    }
15122
15123    /**
15124     * Process any segments that the muxer has output
15125     * Concatenate segments together based on type and append them into
15126     * their respective sourceBuffers
15127     *
15128     * @private
15129     */
15130  }, {
15131    key: 'processPendingSegments_',
15132    value: function processPendingSegments_() {
15133      var sortedSegments = {
15134        video: {
15135          segments: [],
15136          bytes: 0
15137        },
15138        audio: {
15139          segments: [],
15140          bytes: 0
15141        },
15142        captions: [],
15143        metadata: []
15144      };
15145
15146      // Sort segments into separate video/audio arrays and
15147      // keep track of their total byte lengths
15148      sortedSegments = this.pendingBuffers_.reduce(function (segmentObj, segment) {
15149        var type = segment.type;
15150        var data = segment.data;
15151        var initSegment = segment.initSegment;
15152
15153        segmentObj[type].segments.push(data);
15154        segmentObj[type].bytes += data.byteLength;
15155
15156        segmentObj[type].initSegment = initSegment;
15157
15158        // Gather any captions into a single array
15159        if (segment.captions) {
15160          segmentObj.captions = segmentObj.captions.concat(segment.captions);
15161        }
15162
15163        if (segment.info) {
15164          segmentObj[type].info = segment.info;
15165        }
15166
15167        // Gather any metadata into a single array
15168        if (segment.metadata) {
15169          segmentObj.metadata = segmentObj.metadata.concat(segment.metadata);
15170        }
15171
15172        return segmentObj;
15173      }, sortedSegments);
15174
15175      // Create the real source buffers if they don't exist by now since we
15176      // finally are sure what tracks are contained in the source
15177      if (!this.videoBuffer_ && !this.audioBuffer_) {
15178        // Remove any codecs that may have been specified by default but
15179        // are no longer applicable now
15180        if (sortedSegments.video.bytes === 0) {
15181          this.videoCodec_ = null;
15182        }
15183        if (sortedSegments.audio.bytes === 0) {
15184          this.audioCodec_ = null;
15185        }
15186
15187        this.createRealSourceBuffers_();
15188      }
15189
15190      if (sortedSegments.audio.info) {
15191        this.mediaSource_.trigger({ type: 'audioinfo', info: sortedSegments.audio.info });
15192      }
15193      if (sortedSegments.video.info) {
15194        this.mediaSource_.trigger({ type: 'videoinfo', info: sortedSegments.video.info });
15195      }
15196
15197      if (this.appendAudioInitSegment_) {
15198        if (!this.audioDisabled_ && this.audioBuffer_) {
15199          sortedSegments.audio.segments.unshift(sortedSegments.audio.initSegment);
15200          sortedSegments.audio.bytes += sortedSegments.audio.initSegment.byteLength;
15201        }
15202        this.appendAudioInitSegment_ = false;
15203      }
15204
15205      // Merge multiple video and audio segments into one and append
15206      if (this.videoBuffer_) {
15207        sortedSegments.video.segments.unshift(sortedSegments.video.initSegment);
15208        sortedSegments.video.bytes += sortedSegments.video.initSegment.byteLength;
15209        this.concatAndAppendSegments_(sortedSegments.video, this.videoBuffer_);
15210        // TODO: are video tracks the only ones with text tracks?
15211        (0, _addTextTrackData.addTextTrackData)(this, sortedSegments.captions, sortedSegments.metadata);
15212      }
15213      if (!this.audioDisabled_ && this.audioBuffer_) {
15214        this.concatAndAppendSegments_(sortedSegments.audio, this.audioBuffer_);
15215      }
15216
15217      this.pendingBuffers_.length = 0;
15218
15219      // We are no longer in the internal "updating" state
15220      this.bufferUpdating_ = false;
15221    }
15222
15223    /**
15224     * Combine all segments into a single Uint8Array and then append them
15225     * to the destination buffer
15226     *
15227     * @param {Object} segmentObj
15228     * @param {SourceBuffer} destinationBuffer native source buffer to append data to
15229     * @private
15230     */
15231  }, {
15232    key: 'concatAndAppendSegments_',
15233    value: function concatAndAppendSegments_(segmentObj, destinationBuffer) {
15234      var offset = 0;
15235      var tempBuffer = undefined;
15236
15237      if (segmentObj.bytes) {
15238        tempBuffer = new Uint8Array(segmentObj.bytes);
15239
15240        // Combine the individual segments into one large typed-array
15241        segmentObj.segments.forEach(function (segment) {
15242          tempBuffer.set(segment, offset);
15243          offset += segment.byteLength;
15244        });
15245
15246        destinationBuffer.appendBuffer(tempBuffer);
15247      }
15248    }
15249
15250    /**
15251     * Emulate the native mediasource function. abort any soureBuffer
15252     * actions and throw out any un-appended data.
15253     *
15254     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/abort
15255     */
15256  }, {
15257    key: 'abort',
15258    value: function abort() {
15259      if (this.videoBuffer_) {
15260        this.videoBuffer_.abort();
15261      }
15262      if (this.audioBuffer_) {
15263        this.audioBuffer_.abort();
15264      }
15265      if (this.transmuxer_) {
15266        this.transmuxer_.postMessage({ action: 'reset' });
15267      }
15268      this.pendingBuffers_.length = 0;
15269      this.bufferUpdating_ = false;
15270    }
15271  }]);
15272
15273  return VirtualSourceBuffer;
15274})(_videoJs2['default'].EventTarget);
15275
15276exports['default'] = VirtualSourceBuffer;
15277module.exports = exports['default'];
15278}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
15279},{"./add-text-track-data":84,"./codec-utils":85,"./create-text-tracks-if-necessary":86,"./remove-cues-from-track":91,"./transmuxer-worker":92,"webworkify":95}],95:[function(require,module,exports){
15280var bundleFn = arguments[3];
15281var sources = arguments[4];
15282var cache = arguments[5];
15283
15284var stringify = JSON.stringify;
15285
15286module.exports = function (fn) {
15287    var keys = [];
15288    var wkey;
15289    var cacheKeys = Object.keys(cache);
15290    
15291    for (var i = 0, l = cacheKeys.length; i < l; i++) {
15292        var key = cacheKeys[i];
15293        if (cache[key].exports === fn) {
15294            wkey = key;
15295            break;
15296        }
15297    }
15298    
15299    if (!wkey) {
15300        wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
15301        var wcache = {};
15302        for (var i = 0, l = cacheKeys.length; i < l; i++) {
15303            var key = cacheKeys[i];
15304            wcache[key] = key;
15305        }
15306        sources[wkey] = [
15307            Function(['require','module','exports'], '(' + fn + ')(self)'),
15308            wcache
15309        ];
15310    }
15311    var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
15312    
15313    var scache = {}; scache[wkey] = wkey;
15314    sources[skey] = [
15315        Function(['require'],'require(' + stringify(wkey) + ')(self)'),
15316        scache
15317    ];
15318    
15319    var src = '(' + bundleFn + ')({'
15320        + Object.keys(sources).map(function (key) {
15321            return stringify(key) + ':['
15322                + sources[key][0]
15323                + ',' + stringify(sources[key][1]) + ']'
15324            ;
15325        }).join(',')
15326        + '},{},[' + stringify(skey) + '])'
15327    ;
15328    
15329    var URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
15330    
15331    return new Worker(URL.createObjectURL(
15332        new Blob([src], { type: 'text/javascript' })
15333    ));
15334};
15335
15336},{}],96:[function(require,module,exports){
15337(function (global){
15338/**
15339 * @file videojs-contrib-hls.js
15340 *
15341 * The main file for the HLS project.
15342 * License: https://github.com/videojs/videojs-contrib-hls/blob/master/LICENSE
15343 */
15344'use strict';
15345
15346var _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; }; })();
15347
15348var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; 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 { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
15349
15350function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
15351
15352function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
15353
15354function _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, { c
15354onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
15355
15356var _globalDocument = require('global/document');
15357
15358var _globalDocument2 = _interopRequireDefault(_globalDocument);
15359
15360var _playlistLoader = require('./playlist-loader');
15361
15362var _playlistLoader2 = _interopRequireDefault(_playlistLoader);
15363
15364var _playlist = require('./playlist');
15365
15366var _playlist2 = _interopRequireDefault(_playlist);
15367
15368var _xhr = require('./xhr');
15369
15370var _xhr2 = _interopRequireDefault(_xhr);
15371
15372var _aesDecrypter = require('aes-decrypter');
15373
15374var _binUtils = require('./bin-utils');
15375
15376var _binUtils2 = _interopRequireDefault(_binUtils);
15377
15378var _videojsContribMediaSources = require('videojs-contrib-media-sources');
15379
15380var _m3u8Parser = require('m3u8-parser');
15381
15382var _m3u8Parser2 = _interopRequireDefault(_m3u8Parser);
15383
15384var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
15385
15386var _videoJs2 = _interopRequireDefault(_videoJs);
15387
15388var _masterPlaylistController = require('./master-playlist-controller');
15389
15390var _config = require('./config');
15391
15392var _config2 = _interopRequireDefault(_config);
15393
15394var _renditionMixin = require('./rendition-mixin');
15395
15396var _renditionMixin2 = _interopRequireDefault(_renditionMixin);
15397
15398var _gapSkipper = require('./gap-skipper');
15399
15400var _gapSkipper2 = _interopRequireDefault(_gapSkipper);
15401
15402var _globalWindow = require('global/window');
15403
15404var _globalWindow2 = _interopRequireDefault(_globalWindow);
15405
15406var Hls = {
15407  PlaylistLoader: _playlistLoader2['default'],
15408  Playlist: _playlist2['default'],
15409  Decrypter: _aesDecrypter.Decrypter,
15410  AsyncStream: _aesDecrypter.AsyncStream,
15411  decrypt: _aesDecrypter.decrypt,
15412  utils: _binUtils2['default'],
15413  xhr: (0, _xhr2['default'])()
15414};
15415
15416Object.defineProperty(Hls, 'GOAL_BUFFER_LENGTH', {
15417  get: function get() {
15418    _videoJs2['default'].log.warn('using Hls.GOAL_BUFFER_LENGTH is UNSAFE be sure ' + 'you know what you are doing');
15419    return _config2['default'].GOAL_BUFFER_LENGTH;
15420  },
15421  set: function set(v) {
15422    _videoJs2['default'].log.warn('using Hls.GOAL_BUFFER_LENGTH is UNSAFE be sure ' + 'you know what you are doing');
15423    if (typeof v !== 'number' || v <= 0) {
15424      _videoJs2['default'].log.warn('value passed to Hls.GOAL_BUFFER_LENGTH ' + 'must be a number and greater than 0');
15425      return;
15426    }
15427    _config2['default'].GOAL_BUFFER_LENGTH = v;
15428  }
15429});
15430
15431// A fudge factor to apply to advertised playlist bitrates to account for
15432// temporary flucations in client bandwidth
15433var BANDWIDTH_VARIANCE = 1.2;
15434
15435/**
15436 * Returns the CSS value for the specified property on an element
15437 * using `getComputedStyle`. Firefox has a long-standing issue where
15438 * getComputedStyle() may return null when running in an iframe with
15439 * `display: none`.
15440 *
15441 * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397
15442 * @param {HTMLElement} el the htmlelement to work on
15443 * @param {string} the proprety to get the style for
15444 */
15445var safeGetComputedStyle = function safeGetComputedStyle(el, property) {
15446  var result = undefined;
15447
15448  if (!el) {
15449    return '';
15450  }
15451
15452  result = _globalWindow2['default'].getComputedStyle(el);
15453  if (!result) {
15454    return '';
15455  }
15456
15457  return result[property];
15458};
15459
15460/**
15461 * Chooses the appropriate media playlist based on the current
15462 * bandwidth estimate and the player size.
15463 *
15464 * @return {Playlist} the highest bitrate playlist less than the currently detected
15465 * bandwidth, accounting for some amount of bandwidth variance
15466 */
15467Hls.STANDARD_PLAYLIST_SELECTOR = function () {
15468  var effectiveBitrate = undefined;
15469  var sortedPlaylists = this.playlists.master.playlists.slice();
15470  var bandwidthPlaylists = [];
15471  var now = +new Date();
15472  var i = undefined;
15473  var variant = undefined;
15474  var bandwidthBestVariant = undefined;
15475  var resolutionPlusOne = undefined;
15476  var resolutionPlusOneAttribute = undefined;
15477  var resolutionBestVariant = undefined;
15478  var width = undefined;
15479  var height = undefined;
15480
15481  sortedPlaylists.sort(Hls.comparePlaylistBandwidth);
15482
15483  // filter out any playlists that have been excluded due to
15484  // incompatible configurations or playback errors
15485  sortedPlaylists = sortedPlaylists.filter(function (localVariant) {
15486    if (typeof localVariant.excludeUntil !== 'undefined') {
15487      return now >= localVariant.excludeUntil;
15488    }
15489    return true;
15490  });
15491
15492  // filter out any variant that has greater effective bitrate
15493  // than the current estimated bandwidth
15494  i = sortedPlaylists.length;
15495  while (i--) {
15496    variant = sortedPlaylists[i];
15497
15498    // ignore playlists without bandwidth information
15499    if (!variant.attributes || !variant.attributes.BANDWIDTH) {
15500      continue;
15501    }
15502
15503    effectiveBitrate = variant.attributes.BANDWIDTH * BANDWIDTH_VARIANCE;
15504
15505    if (effectiveBitrate < this.bandwidth) {
15506      bandwidthPlaylists.push(variant);
15507
15508      // since the playlists are sorted in ascending order by
15509      // bandwidth, the first viable variant is the best
15510      if (!bandwidthBestVariant) {
15511        bandwidthBestVariant = variant;
15512      }
15513    }
15514  }
15515
15516  i = bandwidthPlaylists.length;
15517
15518  // sort variants by resolution
15519  bandwidthPlaylists.sort(Hls.comparePlaylistResolution);
15520
15521  // forget our old variant from above,
15522  // or we might choose that in high-bandwidth scenarios
15523  // (this could be the lowest bitrate rendition as  we go through all of them above)
15524  variant = null;
15525
15526  width = parseInt(safeGetComputedStyle(this.tech_.el(), 'width'), 10);
15527  height = parseInt(safeGetComputedStyle(this.tech_.el(), 'height'), 10);
15528
15529  // iterate through the bandwidth-filtered playlists and find
15530  // best rendition by player dimension
15531  while (i--) {
15532    variant = bandwidthPlaylists[i];
15533
15534    // ignore playlists without resolution information
15535    if (!variant.attributes || !variant.attributes.RESOLUTION || !variant.attributes.RESOLUTION.width || !variant.attributes.RESOLUTION.height) {
15536      continue;
15537    }
15538
15539    // since the playlists are sorted, the first variant that has
15540    // dimensions less than or equal to the player size is the best
15541    var variantResolution = variant.attributes.RESOLUTION;
15542
15543    if (variantResolution.width === width && variantResolution.height === height) {
15544      // if we have the exact resolution as the player use it
15545      resolutionPlusOne = null;
15546      resolutionBestVariant = variant;
15547      break;
15548    } else if (variantResolution.width < width && variantResolution.height < height) {
15549      // if both dimensions are less than the player use the
15550      // previous (next-largest) variant
15551      break;
15552    } else if (!resolutionPlusOne || variantResolution.width < resolutionPlusOneAttribute.width && variantResolution.height < resolutionPlusOneAttribute.height) {
15553      // If we still haven't found a good match keep a
15554      // reference to the previous variant for the next loop
15555      // iteration
15556
15557      // By only saving variants if they are smaller than the
15558      // previously saved variant, we ensure that we also pick
15559      // the highest bandwidth variant that is just-larger-than
15560      // the video player
15561      resolutionPlusOne = variant;
15562      resolutionPlusOneAttribute = resolutionPlusOne.attributes.RESOLUTION;
15563    }
15564  }
15565
15566  // fallback chain of variants
15567  return resolutionPlusOne || resolutionBestVariant || bandwidthBestVariant || sortedPlaylists[0];
15568};
15569
15570// HLS is a source handler, not a tech. Make sure attempts to use it
15571// as one do not cause exceptions.
15572Hls.canPlaySource = function () {
15573  return _videoJs2['default'].log.warn('HLS is no longer a tech. Please remove it from ' + 'your player\'s techOrder.');
15574};
15575
15576/**
15577 * Whether the browser has built-in HLS support.
15578 */
15579Hls.supportsNativeHls = (function () {
15580  var video = _globalDocument2['default'].createElement('video');
15581
15582  // native HLS is definitely not supported if HTML5 video isn't
15583  if (!_videoJs2['default'].getComponent('Html5').isSupported()) {
15584    return false;
15585  }
15586
15587  // HLS manifests can go by many mime-types
15588  var canPlay = [
15589  // Apple santioned
15590  'application/vnd.apple.mpegurl',
15591  // Apple sanctioned for backwards compatibility
15592  'audio/mpegurl',
15593  // Very common
15594  'audio/x-mpegurl',
15595  // Very common
15596  'application/x-mpegurl',
15597  // Included for completeness
15598  'video/x-mpegurl', 'video/mpegurl', 'application/mpegurl'];
15599
15600  return canPlay.some(function (canItPlay) {
15601    return (/maybe|probably/i.test(video.canPlayType(canItPlay))
15602    );
15603  });
15604})();
15605
15606/**
15607 * HLS is a source handler, not a tech. Make sure attempts to use it
15608 * as one do not cause exceptions.
15609 */
15610Hls.isSupported = function () {
15611  return _videoJs2['default'].log.warn('HLS is no longer a tech. Please remove it from ' + 'your player\'s techOrder.');
15612};
15613
15614var USER_AGENT = _globalWindow2['default'].navigator && _globalWindow2['default'].navigator.userAgent || '';
15615
15616/**
15617 * Determines whether the browser supports a change in the audio configuration
15618 * during playback. Currently only Firefox 48 and below do not support this.
15619 * window.isSecureContext is a propterty that was added to window in firefox 49,
15620 * so we can use it to detect Firefox 49+.
15621 *
15622 * @return {Boolean} Whether the browser supports audio config change during playback
15623 */
15624Hls.supportsAudioInfoChange_ = function () {
15625  if (_videoJs2['default'].browser.IS_FIREFOX) {
15626    var firefoxVersionMap = /Firefox\/([\d.]+)/i.exec(USER_AGENT);
15627    var version = parseInt(firefoxVersionMap[1], 10);
15628
15629    return version >= 49;
15630  }
15631  return true;
15632};
15633
15634var Component = _videoJs2['default'].getComponent('Component');
15635
15636/**
15637 * The Hls Handler object, where we orchestrate all of the parts
15638 * of HLS to interact with video.js
15639 *
15640 * @class HlsHandler
15641 * @extends videojs.Component
15642 * @param {Object} source the soruce object
15643 * @param {Tech} tech the parent tech object
15644 * @param {Object} options optional and required options
15645 */
15646
15647var HlsHandler = (function (_Component) {
15648  _inherits(HlsHandler, _Component);
15649
15650  function HlsHandler(source, tech, options) {
15651    var _this = this;
15652
15653    _classCallCheck(this, HlsHandler);
15654
15655    _get(Object.getPrototypeOf(HlsHandler.prototype), 'constructor', this).call(this, tech);
15656
15657    // tech.player() is deprecated but setup a reference to HLS for
15658    // backwards-compatibility
15659    if (tech.options_ && tech.options_.playerId) {
15660      var _player = (0, _videoJs2['default'])(tech.options_.playerId);
15661
15662      if (!_player.hasOwnProperty('hls')) {
15663        Object.defineProperty(_player, 'hls', {
15664          get: function get() {
15665            _videoJs2['default'].log.warn('player.hls is deprecated. Use player.tech_.hls instead.');
15666            return _this;
15667          }
15668        });
15669      }
15670    }
15671
15672    this.tech_ = tech;
15673    this.source_ = source;
15674    this.stats = {};
15675
15676    // handle global & Source Handler level options
15677    this.options_ = _videoJs2['default'].mergeOptions(_videoJs2['default'].options.hls || {}, options.hls);
15678    this.setOptions_();
15679
15680    // listen for fullscreenchange events for this player so that we
15681    // can adjust our quality selection quickly
15682    this.on(_globalDocument2['default'], ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange'], function (event) {
15683      var fullscreenElement = _globalDocument2['default'].fullscreenElement || _globalDocument2['default'].webkitFullscreenElement || _globalDocument2['default'].mozFullScreenElement || _globalDocument2['default'].msFullscreenElement;
15684
15685      if (fullscreenElement && fullscreenElement.contains(_this.tech_.el())) {
15686        _this.masterPlaylistController_.fastQualityChange_();
15687      }
15688    });
15689
15690    this.on(this.tech_, 'seeking', function () {
15691      this.setCurrentTime(this.tech_.currentTime());
15692    });
15693    this.on(this.tech_, 'error', function () {
15694      if (this.masterPlaylistController_) {
15695        this.masterPlaylistController_.pauseLoading();
15696      }
15697    });
15698
15699    this.audioTrackChange_ = function () {
15700      _this.masterPlaylistController_.setupAudio();
15701    };
15702
15703    this.on(this.tech_, 'play', this.play);
15704  }
15705
15706  /**
15707   * The Source Handler object, which informs video.js what additional
15708   * MIME types are supported and sets up playback. It is registered
15709   * automatically to the appropriate tech based on the capabilities of
15710   * the browser it is running in. It is not necessary to use or modify
15711   * this object in normal usage.
15712   */
15713
15714  _createClass(HlsHandler, [{
15715    key: 'setOptions_',
15716    value: function setOptions_() {
15717      var _this2 = this;
15718
15719      // defaults
15720      this.options_.withCredentials = this.options_.withCredentials || false;
15721
15722      // start playlist selection at a reasonable bandwidth for
15723      // broadband internet
15724      // 0.5 MB/s
15725      if (typeof this.options_.bandwidth !== 'number') {
15726        this.options_.bandwidth = 4194304;
15727      }
15728
15729      // grab options passed to player.src
15730      ['withCredentials', 'bandwidth'].forEach(function (option) {
15731        if (typeof _this2.source_[option] !== 'undefined') {
15732          _this2.options_[option] = _this2.source_[option];
15733        }
15734      });
15735
15736      this.bandwidth = this.options_.bandwidth;
15737    }
15738
15739    /**
15740     * called when player.src gets called, handle a new source
15741     *
15742     * @param {Object} src the source object to handle
15743     */
15744  }, {
15745    key: 'src',
15746    value: function src(_src) {
15747      var _this3 = this;
15748
15749      // do nothing if the src is falsey
15750      if (!_src) {
15751        return;
15752      }
15753      this.setOptions_();
15754      // add master playlist controller options
15755      this.options_.url = this.source_.src;
15756      this.options_.tech = this.tech_;
15757      this.options_.externHls = Hls;
15758      this.masterPlaylistController_ = new _masterPlaylistController.MasterPlaylistController(this.options_);
15759      this.gapSkipper_ = new _gapSkipper2['default'](this.options_);
15760
15761      // `this` in selectPlaylist should be the HlsHandler for backwards
15762      // compatibility with < v2
15763      this.masterPlaylistController_.selectPlaylist = this.selectPlaylist ? this.selectPlaylist.bind(this) : Hls.STANDARD_PLAYLIST_SELECTOR.bind(this);
15764
15765      // re-expose some internal objects for backwards compatibility with < v2
15766      this.playlists = this.masterPlaylistController_.masterPlaylistLoader_;
15767      this.mediaSource = this.masterPlaylistController_.mediaSource;
15768
15769      // Proxy assignment of some properties to the master playlist
15770      // controller. Using a custom property for backwards compatibility
15771      // with < v2
15772      Object.defineProperties(this, {
15773        selectPlaylist: {
15774          get: function get() {
15775            return this.masterPlaylistController_.selectPlaylist;
15776          },
15777          set: function set(selectPlaylist) {
15778            this.masterPlaylistController_.selectPlaylist = selectPlaylist.bind(this);
15779          }
15780        },
15781        bandwidth: {
15782          get: function get() {
15783            return this.masterPlaylistController_.mainSegmentLoader_.bandwidth;
15784          },
15785          set: function set(bandwidth) {
15786            this.masterPlaylistController_.mainSegmentLoader_.bandwidth = bandwidth;
15787          }
15788        }
15789      });
15790
15791      Object.defineProperties(this.stats, {
15792        bandwidth: {
15793          get: function get() {
15794            return _this3.bandwidth || 0;
15795          },
15796          enumerable: true
15797        },
15798        mediaRequests: {
15799          get: function get() {
15800            return _this3.masterPlaylistController_.mediaRequests_() || 0;
15801          },
15802          enumerable: true
15803        },
15804        mediaTransferDuration: {
15805          get: function get() {
15806            return _this3.masterPlaylistController_.mediaTransferDuration_() || 0;
15807          },
15808          enumerable: true
15809        },
15810        mediaBytesTransferred: {
15811          get: function get() {
15812            return _this3.masterPlaylistController_.mediaBytesTransferred_() || 0;
15813          },
15814          enumerable: true
15815        }
15816      });
15817
15818      this.tech_.one('canplay', this.masterPlaylistController_.setupFirstPlay.bind(this.masterPlaylistController_));
15819
15820      this.masterPlaylistController_.on('sourceopen', function () {
15821        _this3.tech_.audioTracks().addEventListener('change', _this3.audioTrackChange_);
15822      });
15823
15824      this.masterPlaylistController_.on('selectedinitialmedia', function () {
15825        // Add the manual rendition mix-in to HlsHandler
15826        (0, _renditionMixin2['default'])(_this3);
15827      });
15828
15829      this.masterPlaylistController_.on('audioupdate', function () {
15830        // clear current audioTracks
15831        _this3.tech_.clearTracks('audio');
15832        _this3.masterPlaylistController_.activeAudioGroup().forEac
15832h(function (audioTrack) {
15833          _this3.tech_.audioTracks().addTrack(audioTrack);
15834        });
15835      });
15836
15837      // the bandwidth of the primary segment loader is our best
15838      // estimate of overall bandwidth
15839      this.on(this.masterPlaylistController_, 'progress', function () {
15840        this.bandwidth = this.masterPlaylistController_.mainSegmentLoader_.bandwidth;
15841        this.tech_.trigger('progress');
15842      });
15843
15844      // do nothing if the tech has been disposed already
15845      // this can occur if someone sets the src in player.ready(), for instance
15846      if (!this.tech_.el()) {
15847        return;
15848      }
15849
15850      this.tech_.src(_videoJs2['default'].URL.createObjectURL(this.masterPlaylistController_.mediaSource));
15851    }
15852
15853    /**
15854     * a helper for grabbing the active audio group from MasterPlaylistController
15855     *
15856     * @private
15857     */
15858  }, {
15859    key: 'activeAudioGroup_',
15860    value: function activeAudioGroup_() {
15861      return this.masterPlaylistController_.activeAudioGroup();
15862    }
15863
15864    /**
15865     * Begin playing the video.
15866     */
15867  }, {
15868    key: 'play',
15869    value: function play() {
15870      this.masterPlaylistController_.play();
15871    }
15872
15873    /**
15874     * a wrapper around the function in MasterPlaylistController
15875     */
15876  }, {
15877    key: 'setCurrentTime',
15878    value: function setCurrentTime(currentTime) {
15879      this.masterPlaylistController_.setCurrentTime(currentTime);
15880    }
15881
15882    /**
15883     * a wrapper around the function in MasterPlaylistController
15884     */
15885  }, {
15886    key: 'duration',
15887    value: function duration() {
15888      return this.masterPlaylistController_.duration();
15889    }
15890
15891    /**
15892     * a wrapper around the function in MasterPlaylistController
15893     */
15894  }, {
15895    key: 'seekable',
15896    value: function seekable() {
15897      return this.masterPlaylistController_.seekable();
15898    }
15899
15900    /**
15901    * Abort all outstanding work and cleanup.
15902    */
15903  }, {
15904    key: 'dispose',
15905    value: function dispose() {
15906      if (this.masterPlaylistController_) {
15907        this.masterPlaylistController_.dispose();
15908      }
15909      this.gapSkipper_.dispose();
15910      this.tech_.audioTracks().removeEventListener('change', this.audioTrackChange_);
15911      _get(Object.getPrototypeOf(HlsHandler.prototype), 'dispose', this).call(this);
15912    }
15913  }]);
15914
15915  return HlsHandler;
15916})(Component);
15917
15918var HlsSourceHandler = function HlsSourceHandler(mode) {
15919  return {
15920    canHandleSource: function canHandleSource(srcObj) {
15921      // this forces video.js to skip this tech/mode if its not the one we have been
15922      // overriden to use, by returing that we cannot handle the source.
15923      if (_videoJs2['default'].options.hls && _videoJs2['default'].options.hls.mode && _videoJs2['default'].options.hls.mode !== mode) {
15924        return false;
15925      }
15926      return HlsSourceHandler.canPlayType(srcObj.type);
15927    },
15928    handleSource: function handleSource(source, tech, options) {
15929      if (mode === 'flash') {
15930        // We need to trigger this asynchronously to give others the chance
15931        // to bind to the event when a source is set at player creation
15932        tech.setTimeout(function () {
15933          tech.trigger('loadstart');
15934        }, 1);
15935      }
15936
15937      var settings = _videoJs2['default'].mergeOptions(options, { hls: { mode: mode } });
15938
15939      tech.hls = new HlsHandler(source, tech, settings);
15940
15941      tech.hls.xhr = (0, _xhr2['default'])();
15942      // Use a global `before` function if specified on videojs.Hls.xhr
15943      // but still allow for a per-player override
15944      if (_videoJs2['default'].Hls.xhr.beforeRequest) {
15945        tech.hls.xhr.beforeRequest = _videoJs2['default'].Hls.xhr.beforeRequest;
15946      }
15947
15948      tech.hls.src(source.src);
15949      return tech.hls;
15950    },
15951    canPlayType: function canPlayType(type) {
15952      if (HlsSourceHandler.canPlayType(type)) {
15953        return 'maybe';
15954      }
15955      return '';
15956    }
15957  };
15958};
15959
15960/**
15961 * A comparator function to sort two playlist object by bandwidth.
15962 *
15963 * @param {Object} left a media playlist object
15964 * @param {Object} right a media playlist object
15965 * @return {Number} Greater than zero if the bandwidth attribute of
15966 * left is greater than the corresponding attribute of right. Less
15967 * than zero if the bandwidth of right is greater than left and
15968 * exactly zero if the two are equal.
15969 */
15970Hls.comparePlaylistBandwidth = function (left, right) {
15971  var leftBandwidth = undefined;
15972  var rightBandwidth = undefined;
15973
15974  if (left.attributes && left.attributes.BANDWIDTH) {
15975    leftBandwidth = left.attributes.BANDWIDTH;
15976  }
15977  leftBandwidth = leftBandwidth || _globalWindow2['default'].Number.MAX_VALUE;
15978  if (right.attributes && right.attributes.BANDWIDTH) {
15979    rightBandwidth = right.attributes.BANDWIDTH;
15980  }
15981  rightBandwidth = rightBandwidth || _globalWindow2['default'].Number.MAX_VALUE;
15982
15983  return leftBandwidth - rightBandwidth;
15984};
15985
15986/**
15987 * A comparator function to sort two playlist object by resolution (width).
15988 * @param {Object} left a media playlist object
15989 * @param {Object} right a media playlist object
15990 * @return {Number} Greater than zero if the resolution.width attribute of
15991 * left is greater than the corresponding attribute of right. Less
15992 * than zero if the resolution.width of right is greater than left and
15993 * exactly zero if the two are equal.
15994 */
15995Hls.comparePlaylistResolution = function (left, right) {
15996  var leftWidth = undefined;
15997  var rightWidth = undefined;
15998
15999  if (left.attributes && left.attributes.RESOLUTION && left.attributes.RESOLUTION.width) {
16000    leftWidth = left.attributes.RESOLUTION.width;
16001  }
16002
16003  leftWidth = leftWidth || _globalWindow2['default'].Number.MAX_VALUE;
16004
16005  if (right.attributes && right.attributes.RESOLUTION && right.attributes.RESOLUTION.width) {
16006    rightWidth = right.attributes.RESOLUTION.width;
16007  }
16008
16009  rightWidth = rightWidth || _globalWindow2['default'].Number.MAX_VALUE;
16010
16011  // NOTE - Fallback to bandwidth sort as appropriate in cases where multiple renditions
16012  // have the same media dimensions/ resolution
16013  if (leftWidth === rightWidth && left.attributes.BANDWIDTH && right.attributes.BANDWIDTH) {
16014    return left.attributes.BANDWIDTH - right.attributes.BANDWIDTH;
16015  }
16016  return leftWidth - rightWidth;
16017};
16018
16019HlsSourceHandler.canPlayType = function (type) {
16020  var mpegurlRE = /^(audio|video|application)\/(x-|vnd\.apple\.)?mpegurl/i;
16021
16022  // favor native HLS support if it's available
16023  if (Hls.supportsNativeHls) {
16024    return false;
16025  }
16026  return mpegurlRE.test(type);
16027};
16028
16029if (typeof _videoJs2['default'].MediaSource === 'undefined' || typeof _videoJs2['default'].URL === 'undefined') {
16030  _videoJs2['default'].MediaSource = _videojsContribMediaSources.MediaSource;
16031  _videoJs2['default'].URL = _videojsContribMediaSources.URL;
16032}
16033
16034// register source handlers with the appropriate techs
16035if (_videojsContribMediaSources.MediaSource.supportsNativeMediaSources()) {
16036  _videoJs2['default'].getComponent('Html5').registerSourceHandler(HlsSourceHandler('html5'));
16037}
16038if (_globalWindow2['default'].Uint8Array) {
16039  _videoJs2['default'].getComponent('Flash').registerSourceHandler(HlsSourceHandler('flash'));
16040}
16041
16042_videoJs2['default'].HlsHandler = HlsHandler;
16043_videoJs2['default'].HlsSourceHandler = HlsSourceHandler;
16044_videoJs2['default'].Hls = Hls;
16045_videoJs2['default'].m3u8 = _m3u8Parser2['default'];
16046_videoJs2['default'].registerComponent('Hls', Hls);
16047_videoJs2['default'].options.hls = _videoJs2['default'].options.hls || {};
16048
16049module.exports = {
16050  Hls: Hls,
16051  HlsHandler: HlsHandler,
16052  HlsSourceHandler: HlsSourceHandler
16053};
16054}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
16055},{"./bin-utils":2,"./config":3,"./gap-skipper":4,"./master-playlist-controller":5,"./playlist":7,"./playlist-loader":6,"./rendition-mixin":9,"./xhr":14,"aes-decrypter":18,"global/document":24,"global/window":25,"m3u8-parser":62,"videojs-contrib-media-sources":93}]},{},[96])(96)
16056});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.