2013-01-10 13:06:12 -08:00
|
|
|
/**
|
|
|
|
* @fileoverview HTML5 Media Controller - Wrapper for HTML5 Media API
|
|
|
|
*/
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-12 22:23:22 -08:00
|
|
|
goog.provide('vjs.Html5');
|
|
|
|
|
|
|
|
goog.require('vjs.MediaTechController');
|
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
/**
|
|
|
|
* HTML5 Media Controller - Wrapper for HTML5 Media API
|
2013-01-04 16:58:23 -08:00
|
|
|
* @param {vjs.Player|Object} player
|
2012-12-30 21:45:50 -08:00
|
|
|
* @param {Object=} options
|
|
|
|
* @param {Function=} ready
|
|
|
|
* @constructor
|
|
|
|
*/
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5 = function(player, options, ready){
|
2012-12-30 21:45:50 -08:00
|
|
|
goog.base(this, player, options, ready);
|
|
|
|
|
|
|
|
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) {
|
2013-01-10 13:06:12 -08:00
|
|
|
player.trigger('loadstart');
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// Otherwise set the source if one was provided.
|
|
|
|
} else if (source) {
|
|
|
|
this.el_.src = source.src;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.options.autoplay && this.paused()) {
|
|
|
|
this.tag.poster = null; // Chrome Fix. Fixed in Chrome v16.
|
|
|
|
this.play();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
this.on('click', this.onClick);
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
this.setupTriggers();
|
|
|
|
|
|
|
|
this.triggerReady();
|
|
|
|
};
|
2013-01-04 16:58:23 -08:00
|
|
|
goog.inherits(vjs.Html5, vjs.MediaTechController);
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.dispose = function(){
|
2013-01-16 20:24:38 -05:00
|
|
|
// this.player_.tag = false;
|
2012-12-30 21:45:50 -08:00
|
|
|
this.removeTriggers();
|
|
|
|
|
|
|
|
goog.base(this, 'dispose');
|
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.createEl = function(){
|
2013-01-16 20:24:38 -05:00
|
|
|
var player = this.player_,
|
2012-12-30 21:45:50 -08:00
|
|
|
// If possible, reuse original tag for HTML5 playback technology element
|
|
|
|
el = player.tag,
|
|
|
|
newEl;
|
|
|
|
|
|
|
|
// 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.
|
2013-01-04 16:58:23 -08:00
|
|
|
if (!el || this.features.movingMediaElementInDOM === false) {
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// If the original tag is still there, remove it.
|
|
|
|
if (el) {
|
2013-01-10 13:06:12 -08:00
|
|
|
player.el().removeChild(el);
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
newEl = vjs.createElement('video', {
|
|
|
|
id: el.id || player.id + '_html5_api',
|
|
|
|
className: el.className || 'vjs-tech'
|
2012-12-30 21:45:50 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
el = newEl;
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.insertFirst(el, player.el);
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update specific tag settings, in case they were overridden
|
2013-01-10 13:06:12 -08:00
|
|
|
var attrs = ['autoplay','preload','loop','muted'];
|
2012-12-30 21:45:50 -08:00
|
|
|
for (var i = attrs.length - 1; i >= 0; i--) {
|
|
|
|
var attr = attrs[i];
|
|
|
|
if (player.options[attr] !== null) {
|
|
|
|
el[attr] = player.options[attr];
|
|
|
|
}
|
2013-01-10 13:06:12 -08:00
|
|
|
}
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
return el;
|
|
|
|
// jenniisawesome = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Make video events trigger player events
|
|
|
|
// May seem verbose here, but makes other APIs possible.
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.setupTriggers = function(){
|
|
|
|
for (var i = vjs.Html5.Events.length - 1; i >= 0; i--) {
|
2013-01-16 20:24:38 -05:00
|
|
|
vjs.on(this.el_, vjs.Html5.Events[i], vjs.bind(this.player_, this.eventHandler));
|
2013-01-10 13:06:12 -08:00
|
|
|
}
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.removeTriggers = function(){
|
|
|
|
for (var i = vjs.Html5.Events.length - 1; i >= 0; i--) {
|
2013-01-16 20:24:38 -05:00
|
|
|
vjs.off(this.el_, vjs.Html5.Events[i], vjs.bind(this.player_, this.eventHandler));
|
2013-01-10 13:06:12 -08:00
|
|
|
}
|
|
|
|
// console.log('removeTriggers', vjs.getData(this.el_));
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.eventHandler = function(e){
|
2012-12-30 21:45:50 -08:00
|
|
|
// console.log('eventHandler', e.type, e, this.el_)
|
|
|
|
this.trigger(e);
|
|
|
|
e.stopPropagation();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
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; };
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.currentTime = function(){ return this.el_.currentTime; };
|
|
|
|
vjs.Html5.prototype.setCurrentTime = function(seconds){
|
2012-12-30 21:45:50 -08:00
|
|
|
try {
|
|
|
|
this.el_.currentTime = seconds;
|
|
|
|
} catch(e) {
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.log(e, 'Video is not ready. (Video.js)');
|
2012-12-30 21:45:50 -08:00
|
|
|
// this.warning(VideoJS.warnings.videoNotReady);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.duration = function(){ return this.el_.duration || 0; };
|
|
|
|
vjs.Html5.prototype.buffered = function(){ return this.el_.buffered; };
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
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; };
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.width = function(){ return this.el_.offsetWidth; };
|
|
|
|
vjs.Html5.prototype.height = function(){ return this.el_.offsetHeight; };
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.supportsFullScreen = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
if (typeof this.el_.webkitEnterFullScreen == 'function') {
|
|
|
|
|
|
|
|
// Seems to be broken in Chromium/Chrome && Safari in Leopard
|
2013-01-10 13:06:12 -08:00
|
|
|
if (!navigator.userAgent.match('Chrome') && !navigator.userAgent.match('Mac OS X 10.5')) {
|
2012-12-30 21:45:50 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.enterFullScreen = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
try {
|
|
|
|
this.el_.webkitEnterFullScreen();
|
|
|
|
} catch (e) {
|
|
|
|
if (e.code == 11) {
|
|
|
|
// this.warning(VideoJS.warnings.videoNotReady);
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.log('Video.js: Video not ready.');
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.exitFullScreen = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
try {
|
|
|
|
this.el_.webkitExitFullScreen();
|
|
|
|
} catch (e) {
|
|
|
|
if (e.code == 11) {
|
|
|
|
// this.warning(VideoJS.warnings.videoNotReady);
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.log('Video.js: Video not ready.');
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2013-01-04 16:58:23 -08:00
|
|
|
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.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.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; };
|
2012-12-30 21:45:50 -08:00
|
|
|
// networkState: function(){ return this.el_.networkState; },
|
|
|
|
// readyState: function(){ return this.el_.readyState; },
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.seeking = function(){ return this.el_.seeking; };
|
2012-12-30 21:45:50 -08:00
|
|
|
// initialTime: function(){ return this.el_.initialTime; },
|
|
|
|
// startOffsetTime: function(){ return this.el_.startOffsetTime; },
|
|
|
|
// played: function(){ return this.el_.played; },
|
|
|
|
// seekable: function(){ return this.el_.seekable; },
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.ended = function(){ return this.el_.ended; };
|
2012-12-30 21:45:50 -08:00
|
|
|
// videoTracks: function(){ return this.el_.videoTracks; },
|
|
|
|
// audioTracks: function(){ return this.el_.audioTracks; },
|
|
|
|
// videoWidth: function(){ return this.el_.videoWidth; },
|
|
|
|
// videoHeight: function(){ return this.el_.videoHeight; },
|
|
|
|
// textTracks: function(){ return this.el_.textTracks; },
|
|
|
|
// defaultPlaybackRate: function(){ return this.el_.defaultPlaybackRate; },
|
|
|
|
// playbackRate: function(){ return this.el_.playbackRate; },
|
|
|
|
// mediaGroup: function(){ return this.el_.mediaGroup; },
|
|
|
|
// controller: function(){ return this.el_.controller; },
|
2013-01-16 20:24:38 -05:00
|
|
|
vjs.Html5.prototype.controls = function(){ return this.player_.options.controls; };
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.prototype.defaultMuted = function(){ return this.el_.defaultMuted; };
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
/* HTML5 Support Testing ---------------------------------------------------- */
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.isSupported = function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
return !!document.createElement('video').canPlayType;
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Html5.canPlaySource = function(srcObj){
|
2013-01-10 13:06:12 -08:00
|
|
|
return !!document.createElement('video').canPlayType(srcObj.type);
|
2012-12-30 21:45:50 -08:00
|
|
|
// TODO: Check Type
|
|
|
|
// If no Type, check ext
|
|
|
|
// Check Media Type
|
|
|
|
};
|
|
|
|
|
|
|
|
// List of all HTML5 events (various uses).
|
2013-01-10 13:06:12 -08:00
|
|
|
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(',');
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
// HTML5 Feature detection and Device Fixes --------------------------------- //
|
|
|
|
vjs.Html5.prototype.features = {
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// Support for video element specific full screen. (webkitEnterFullScreen, not requestFullscreen which we use on the player div)
|
|
|
|
// http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html
|
|
|
|
// Seems to be broken in Chromium/Chrome && Safari in Leopard
|
2013-01-04 16:58:23 -08:00
|
|
|
fullscreen: (vjs.TEST_VID.webkitEnterFullScreen)
|
2013-01-10 13:06:12 -08:00
|
|
|
? ((!vjs.USER_AGENT.match('Chrome') && !vjs.USER_AGENT.match('Mac OS X 10.5')
|
2013-01-04 16:58:23 -08:00
|
|
|
? true
|
|
|
|
: false))
|
|
|
|
: false,
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// In iOS, if you move a video element in the DOM, it breaks video playback.
|
2013-01-04 16:58:23 -08:00
|
|
|
movingMediaElementInDOM: !vjs.IS_IOS
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// Android
|
2013-01-04 16:58:23 -08:00
|
|
|
if (vjs.IS_ANDROID) {
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// Override Android 2.2 and less canPlayType method which is broken
|
2013-01-04 16:58:23 -08:00
|
|
|
if (vjs.ANDROID_VERSION < 3) {
|
2013-01-10 13:06:12 -08:00
|
|
|
document.createElement('video').constructor.prototype.canPlayType = function(type){
|
|
|
|
return (type && type.toLowerCase().indexOf('video/mp4') != -1) ? 'maybe' : '';
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|