text: /**
   * @fileoverview HTML5 Media Controller - Wrapper for HTML5 Media API
   */
  
  /**
   * HTML5 Media Controller - Wrapper for HTML5 Media API
   * @param {vjs.Player|Object} player
   * @param {Object=} options
   * @param {Function=} ready
   * @constructor
   */
  vjs.Html5 = vjs.MediaTechController.extend({
    /** @constructor */
    init: function(player, options, ready){
      // volume cannot be changed from 1 on iOS
      this.features['volumeControl'] = vjs.Html5.canControlVolume();
  
      // just in case; or is it excessively...
      this.features['playbackRate'] = vjs.Html5.canControlPlaybackRate();
  
      // In iOS, if you move a video element in the DOM, it breaks video playback.
      this.features['movingMediaElementInDOM'] = !vjs.IS_IOS;
  
      // HTML video is able to automatically resize when going to fullscreen
      this.features['fullscreenResize'] = true;
  
      vjs.MediaTechController.call(this, player, options, ready);
      this.setupTriggers();
  
      var source = options['source'];
  
      // If the element source is already set, we may have missed the loadstart event, and want to trigger it.
      // We don't want to set the source again and interrupt playback.
      if (source && this.el_.currentSrc === source.src && this.el_.networkState > 0) {
        player.trigger('loadstart');
      // Otherwise set the source if one was provided.
      } else if (source) {
        this.el_.src = source.src;
      }
  
      // Determine if native controls should be used
      // Our goal should be to get the custom controls on mobile solid everywhere
      // so we can remove this all together. Right now this will block custom
      // controls on touch enabled laptops like the Chrome Pixel
      if (vjs.TOUCH_ENABLED && player.options()['nativeControlsForTouch'] !== false) {
        this.useNativeControls();
      }
  
      // Chrome and Safari both have issues with autoplay.
      // In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work.
      // In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays)
      // This fixes both issues. Need to wait for API, so it updates displays correctly
      player.ready(function(){
        if (this.tag && this.options_['autoplay'] && this.paused()) {
          delete this.tag['poster']; // Chrome Fix. Fixed in Chrome v16.
          this.play();
        }
      });
  
      this.triggerReady();
    }
  });
  
  vjs.Html5.prototype.dispose = function(){
    vjs.MediaTechController.prototype.dispose.call(this);
  };
  
  vjs.Html5.prototype.createEl = function(){
    var player = this.player_,
        // If possible, reuse original tag for HTML5 playback technology element
        el = player.tag,
        newEl,
        clone;
  
    // Check if this browser supports moving the element into the box.
    // On the iPhone video will break if you move the element,
    // So we have to create a brand new element.
    if (!el || this.features['movingMediaElementInDOM'] === false) {
  
      // If the original tag is still there, clone and remove it.
      if (el) {
        clone = el.cloneNode(false);
        vjs.Html5.disposeMediaElement(el);
        el = clone;
        player.tag = null;
      } else {
        el = vjs.createEl('video', {
          id:player.id() + '_html5_api',
          className:'vjs-tech'
        });
      }
      // associate the player with the new tag
      el['player'] = player;
  
      vjs.insertFirst(el, player.el());
    }
  
    // Update specific tag settings, in case they were overridden
    var attrs = ['autoplay','preload','loop','muted'];
    for (var i = attrs.length - 1; i >= 0; i--) {
      var attr = attrs[i];
      if (player.options_[attr] !== null) {
        el[attr] = player.options_[attr];
      }
    }
  
    return el;
    // jenniisawesome = true;
  };
  
  // Make video events trigger player events
  // May seem verbose here, but makes other APIs possible.
  // Triggers removed using this.off when disposed
  vjs.Html5.prototype.setupTriggers = function(){
    for (var i = vjs.Html5.Events.length - 1; i >= 0; i--) {
      vjs.on(this.el_, vjs.Html5.Events[i], vjs.bind(this, this.eventHandler));
    }
  };
  
  vjs.Html5.prototype.eventHandler = function(evt){
    // In the case of an error, set the error prop on the player
    // and let the player handle triggering the event.
    if (evt.type == 'error') {
      this.player().error(this.error().code);
  
    // in some cases we pass the event directly to the player
    } else {
      // No need for media events to bubble up.
      evt.bubbles = false;
  
      this.player().trigger(evt);
    }
  };
  
  vjs.Html5.prototype.useNativeControls = function(){
    var tech, player, controlsOn, controlsOff, cleanUp;
  
    tech = this;
    player = this.player();
  
    // If the player controls are enabled turn on the native controls
    tech.setControls(player.controls());
  
    // Update the native controls when player controls state is updated
    controlsOn = function(){
      tech.setControls(true);
    };
    controlsOff = function(){
      tech.setControls(false);
    };
    player.on('controlsenabled', controlsOn);
    player.on('controlsdisabled', controlsOff);
  
    // Clean up when not using native controls anymore
    cleanUp = function(){
      player.off('controlsenabled', controlsOn);
      player.off('controlsdisabled', controlsOff);
    };
    tech.on('dispose', cleanUp);
    player.on('usingcustomcontrols', cleanUp);
  
    // Update the state of the player to using native controls
    player.usingNativeControls(true);
  };
  
  
  vjs.Html5.prototype.play = function(){ this.el_.play(); };
  vjs.Html5.prototype.pause = function(){ this.el_.pause(); };
  vjs.Html5.prototype.paused = function(){ return this.el_.paused; };
  
  vjs.Html5.prototype.currentTime = function(){ return this.el_.currentTime; };
  vjs.Html5.prototype.setCurrentTime = function(seconds){
    try {
      this.el_.currentTime = seconds;
    } catch(e) {
      vjs.log(e, 'Video is not ready. (Video.js)');
      // this.warning(VideoJS.warnings.videoNotReady);
    }
  };
  
  vjs.Html5.prototype.duration = function(){ return this.el_.duration || 0; };
  vjs.Html5.prototype.buffered = function(){ return this.el_.buffered; };
  
  vjs.Html5.prototype.volume = function(){ return this.el_.volume; };
  vjs.Html5.prototype.setVolume = function(percentAsDecimal){ this.el_.volume = percentAsDecimal; };
  vjs.Html5.prototype.muted = function(){ return this.el_.muted; };
  vjs.Html5.prototype.setMuted = function(muted){ this.el_.muted = muted; };
  
  vjs.Html5.prototype.width = function(){ return this.el_.offsetWidth; };
  vjs.Html5.prototype.height = function(){ return this.el_.offsetHeight; };
  
  vjs.Html5.prototype.supportsFullScreen = function(){
    if (typeof this.el_.webkitEnterFullScreen == 'function') {
  
      // Seems to be broken in Chromium/Chrome && Safari in Leopard
      if (/Android/.test(vjs.USER_AGENT) || !/Chrome|Mac OS X 10.5/.test(vjs.USER_AGENT)) {
        return true;
      }
    }
    return false;
  };
  
  vjs.Html5.prototype.enterFullScreen = function(){
    var video = this.el_;
    if (video.paused && video.networkState <= video.HAVE_METADATA) {
      // attempt to prime the video element for programmatic access
      // this isn't necessary on the desktop but shouldn't hurt
      this.el_.play();
  
      // playing and pausing synchronously during the transition to fullscreen
      // can get iOS ~6.1 devices into a play/pause loop
      setTimeout(function(){
        video.pause();
        video.webkitEnterFullScreen();
      }, 0);
    } else {
      video.webkitEnterFullScreen();
    }
  };
  vjs.Html5.prototype.exitFullScreen = function(){
    this.el_.webkitExitFullScreen();
  };
  vjs.Html5.prototype.src = function(src){ this.el_.src = src; };
  vjs.Html5.prototype.load = function(){ this.el_.load(); };
  vjs.Html5.prototype.currentSrc = function(){ return this.el_.currentSrc; };
  
  vjs.Html5.prototype.poster = function(){ return this.el_.poster; };
  vjs.Html5.prototype.setPoster = function(val){ this.el_.poster = val; };
  
  vjs.Html5.prototype.preload = function(){ return this.el_.preload; };
  vjs.Html5.prototype.setPreload = function(val){ this.el_.preload = val; };
  
  vjs.Html5.prototype.autoplay = function(){ return this.el_.autoplay; };
  vjs.Html5.prototype.setAutoplay = function(val){ this.el_.autoplay = val; };
  
  vjs.Html5.prototype.controls = function(){ return this.el_.controls; };
  vjs.Html5.prototype.setControls = function(val){ this.el_.controls = !!val; };
  
  vjs.Html5.prototype.loop = function(){ return this.el_.loop; };
  vjs.Html5.prototype.setLoop = function(val){ this.el_.loop = val; };
  
  vjs.Html5.prototype.error = function(){ return this.el_.error; };
  vjs.Html5.prototype.seeking = function(){ return this.el_.seeking; };
  vjs.Html5.prototype.ended = function(){ return this.el_.ended; };
  vjs.Html5.prototype.defaultMuted = function(){ return this.el_.defaultMuted; };
  
  vjs.Html5.prototype.playbackRate = function(){ return this.el_.playbackRate; };
  vjs.Html5.prototype.setPlaybackRate = function(val){ this.el_.playbackRate = val; };
  
  /* HTML5 Support Testing ---------------------------------------------------- */
  
  vjs.Html5.isSupported = function(){
    // ie9 with no Media Player is a LIAR! (#984)
    try {
      vjs.TEST_VID['volume'] = 0.5;
    } catch (e) {
      return false;
    }
  
    return !!vjs.TEST_VID.canPlayType;
  };
  
  vjs.Html5.canPlaySource = function(srcObj){
    // IE9 on Windows 7 without MediaPlayer throws an error here
    // https://github.com/videojs/video.js/issues/519
    try {
      return !!vjs.TEST_VID.canPlayType(srcObj.type);
    } catch(e) {
      return '';
    }
    // TODO: Check Type
    // If no Type, check ext
    // Check Media Type
  };
  
  vjs.Html5.canControlVolume = function(){
    var volume =  vjs.TEST_VID.volume;
    vjs.TEST_VID.volume = (volume / 2) + 0.1;
    return volume !== vjs.TEST_VID.volume;
  };
  
  vjs.Html5.canControlPlaybackRate = function(){
    var playbackRate =  vjs.TEST_VID.playbackRate;
    vjs.TEST_VID.playbackRate = (playbackRate / 2) + 0.1;
    return playbackRate !== vjs.TEST_VID.playbackRate;
  };
  
  // HTML5 Feature detection and Device Fixes --------------------------------- //
  (function() {
    var canPlayType,
        mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i,
        mp4RE = /^video\/mp4/i;
  
    vjs.Html5.patchCanPlayType = function() {
      // Android 4.0 and above can play HLS to some extent but it reports being unable to do so
      if (vjs.ANDROID_VERSION >= 4.0) {
        if (!canPlayType) {
          canPlayType = vjs.TEST_VID.constructor.prototype.canPlayType;
        }
  
        vjs.TEST_VID.constructor.prototype.canPlayType = function(type) {
          if (type && mpegurlRE.test(type)) {
            return 'maybe';
          }
          return canPlayType.call(this, type);
        };
      }
  
      // Override Android 2.2 and less canPlayType method which is broken
      if (vjs.IS_OLD_ANDROID) {
        if (!canPlayType) {
          canPlayType = vjs.TEST_VID.constructor.prototype.canPlayType;
        }
  
        vjs.TEST_VID.constructor.prototype.canPlayType = function(type){
          if (type && mp4RE.test(type)) {
            return 'maybe';
          }
          return canPlayType.call(this, type);
        };
      }
    };
  
    vjs.Html5.unpatchCanPlayType = function() {
      var r = vjs.TEST_VID.constructor.prototype.canPlayType;
      vjs.TEST_VID.constructor.prototype.canPlayType = canPlayType;
      canPlayType = null;
      return r;
    };
  
    // by default, patch the video element
    vjs.Html5.patchCanPlayType();
  })();
  
  // List of all HTML5 events (various uses).
  vjs.Html5.Events = 'loadstart,suspend,abort,error,emptied,stalled,loadedmetadata,loadeddata,canplay,canplaythrough,playing,waiting,seeking,seeked,ended,durationchange,timeupdate,progress,play,pause,ratechange,volumechange'.split(',');
  
  vjs.Html5.disposeMediaElement = function(el){
    if (!el) { return; }
  
    el['player'] = null;
  
    if (el.parentNode) {
      el.parentNode.removeChild(el);
    }
  
    // remove any child track or source nodes to prevent their loading
    while(el.hasChildNodes()) {
      el.removeChild(el.firstChild);
    }
  
    // remove any src reference. not setting `src=''` because that causes a warning
    // in firefox
    el.removeAttribute('src');
  
    // force the media element to update its loading state by calling load()
    // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793)
    if (typeof el.load === 'function') {
      // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
      (function() {
        try {
          el.load();
        } catch (e) {
          // not supported
        }
      })();
    }
  };
  