2013-01-12 22:23:22 -08:00
goog . provide ( 'vjs.Player' ) ;
goog . require ( 'vjs.Component' ) ;
2012-12-30 21:45:50 -08:00
/ * *
2013-01-10 13:06:12 -08:00
* Main player class . A player instance is returned by _V _ ( id ) ;
2012-12-30 21:45:50 -08:00
* @ param { Element } tag The original video tag used for configuring options
* @ param { Object = } options Player options
* @ param { Function = } ready Ready callback function
* @ constructor
* /
2013-01-04 16:58:23 -08:00
vjs . Player = function ( tag , options , ready ) {
2012-12-30 21:45:50 -08:00
this . tag = tag ; // Store the original tag used to set options
// Set Options
// The options argument overrides options set in the video tag
// which overrides globally set options.
// This latter part coincides with the load order
// (tag must exist before Player)
var opts = { } ;
2013-01-04 16:58:23 -08:00
vjs . merge ( opts , vjs . options ) ; // Copy Global Defaults
vjs . merge ( opts , this . getTagSettings ( tag ) ) ; // Override with Video Tag Options
vjs . merge ( opts , options ) ; // Override/extend with options from setup call
2012-12-30 21:45:50 -08:00
// Cache for video property values.
this . cache _ = { } ;
// Run base component initializing with new options.
// Builds the element through createEl()
// Inits and embeds any child components in opts
2013-01-04 16:58:23 -08:00
vjs . Component . call ( this , this , opts , ready ) ;
2012-12-30 21:45:50 -08:00
2013-01-17 20:33:53 -05:00
// Firstplay event implimentation. Not sold on the event yet.
// Could probably just check currentTime==0?
this . one ( 'play' , function ( e ) {
var fpEvent = { type : 'firstplay' , target : this . el _ } ;
// Using vjs.trigger so we can check if default was prevented
var keepGoing = vjs . trigger ( this . el _ , fpEvent ) ;
if ( ! keepGoing ) {
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
e . stopImmediatePropagation ( ) ;
}
} ) ;
2013-01-10 13:06:12 -08:00
this . on ( 'ended' , this . onEnded ) ;
this . on ( 'play' , this . onPlay ) ;
this . on ( 'pause' , this . onPause ) ;
this . on ( 'progress' , this . onProgress ) ;
this . on ( 'durationchange' , this . onDurationChange ) ;
this . on ( 'error' , this . onError ) ;
2012-12-30 21:45:50 -08:00
// Make player easily findable by ID
2013-01-10 13:06:12 -08:00
vjs . players [ this . id _ ] = this ;
2012-12-30 21:45:50 -08:00
} ;
2013-01-04 16:58:23 -08:00
goog . inherits ( vjs . Player , vjs . Component ) ;
2011-11-29 11:40:05 -08:00
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . dispose = function ( ) {
2012-12-30 21:45:50 -08:00
// this.isReady_ = false;
2012-04-06 16:42:09 -07:00
2012-12-30 21:45:50 -08:00
// Kill reference to this player
2013-01-10 13:06:12 -08:00
vjs . players [ this . id _ ] = null ;
2013-01-16 20:24:38 -05:00
if ( this . tag && this . tag [ 'player' ] ) { this . tag [ 'player' ] = null ; }
if ( this . el _ && this . el _ [ 'player' ] ) { this . el _ [ 'player' ] = null ; }
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Ensure that tracking progress and time progress will stop and plater deleted
2012-12-31 15:25:56 -08:00
this . stopTrackingProgress ( ) ;
2013-01-17 20:33:53 -05:00
this . stopTrackingCurrentTime ( ) ;
2012-04-06 16:42:09 -07:00
2012-12-30 21:45:50 -08:00
if ( this . tech ) { this . tech . dispose ( ) ; }
2012-04-06 17:14:45 -07:00
2012-12-30 21:45:50 -08:00
// Component dispose
2012-12-31 15:25:56 -08:00
goog . base ( this , 'dispose' ) ;
2012-12-30 21:45:50 -08:00
} ;
2011-11-29 11:40:05 -08:00
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . getTagSettings = function ( tag ) {
2012-12-30 21:45:50 -08:00
var options = {
2013-01-10 13:06:12 -08:00
'sources' : [ ] ,
'tracks' : [ ]
2012-12-30 21:45:50 -08:00
} ;
2011-11-29 11:40:05 -08:00
2013-01-04 16:58:23 -08:00
vjs . merge ( options , vjs . getAttributeValues ( tag ) ) ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Get tag children settings
if ( tag . hasChildNodes ( ) ) {
var child , childName ,
children = tag . childNodes ,
i = 0 ,
j = children . length ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
for ( ; i < j ; i ++ ) {
child = children [ i ] ;
// Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/
childName = child . nodeName . toLowerCase ( ) ;
2011-11-29 11:40:05 -08:00
2013-01-10 13:06:12 -08:00
if ( childName === 'source' ) {
options [ 'sources' ] . push ( vjs . getAttributeValues ( child ) ) ;
2012-05-25 11:59:53 +02:00
2013-01-10 13:06:12 -08:00
} else if ( childName === 'track' ) {
options [ 'tracks' ] . push ( vjs . getAttributeValues ( child ) ) ;
2012-03-09 17:12:38 -08:00
2011-11-30 13:06:32 -08:00
}
}
2012-12-30 21:45:50 -08:00
}
2013-01-10 13:06:12 -08:00
2012-12-30 21:45:50 -08:00
return options ;
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . createEl = function ( ) {
2012-12-30 21:45:50 -08:00
var el = this . el _ = goog . base ( this , 'createEl' , 'div' ) ;
var tag = this . tag ;
// Original tag settings stored in options
// now remove immediately so native controls don't flash.
2013-01-10 13:06:12 -08:00
tag . removeAttribute ( 'controls' ) ;
2012-12-30 21:45:50 -08:00
// Poster will be handled by a manual <img>
2013-01-10 13:06:12 -08:00
tag . removeAttribute ( 'poster' ) ;
2012-12-30 21:45:50 -08:00
// Remove width/height attrs from tag so CSS can make it 100% width/height
2013-01-10 13:06:12 -08:00
tag . removeAttribute ( 'width' ) ;
tag . removeAttribute ( 'height' ) ;
2012-12-30 21:45:50 -08:00
// Empty video tag sources and tracks so the built-in player doesn't use them also.
// This may not be fast enough to stop HTML5 browsers from reading the tags
// so we'll need to turn off any default tracks if we're manually doing
// captions and subtitles. videoElement.textTracks
if ( tag . hasChildNodes ( ) ) {
var nrOfChildNodes = tag . childNodes . length ;
for ( var i = 0 , j = tag . childNodes ; i < nrOfChildNodes ; i ++ ) {
2013-01-10 13:06:12 -08:00
if ( j [ 0 ] . nodeName . toLowerCase ( ) == 'source' || j [ 0 ] . nodeName . toLowerCase ( ) == 'track' ) {
2012-12-30 21:45:50 -08:00
tag . removeChild ( j [ 0 ] ) ;
2011-11-29 11:40:05 -08:00
}
}
2012-12-30 21:45:50 -08:00
}
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Make sure tag ID exists
2013-01-10 13:06:12 -08:00
tag . id = tag . id || 'vjs_video_' + vjs . guid ++ ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Give video tag ID and class to player div
// ID will now reference player box, not the video tag
el . id = tag . id ;
el . className = tag . className ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Update tag id/class for use as HTML5 playback tech
// Might think we should do this after embedding in container so .vjs-tech class
// doesn't flash 100% width/height, but class only applies with .video-js parent
2013-01-10 13:06:12 -08:00
tag . id += '_html5_api' ;
tag . className = 'vjs-tech' ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Make player findable on elements
2013-01-16 20:24:38 -05:00
tag [ 'player' ] = el [ 'player' ] = this ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Default state of video is paused
2013-01-10 13:06:12 -08:00
this . addClass ( 'vjs-paused' ) ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Make box use width/height of tag, or default 300x150
// Enforce with CSS since width/height attrs don't work on divs
2013-01-10 13:06:12 -08:00
this . width ( this . options [ 'width' ] , true ) ; // (true) Skip resize listener on load
this . height ( this . options [ 'height' ] , true ) ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Wrap video tag in div (el/box) container
if ( tag . parentNode ) {
tag . parentNode . insertBefore ( el , tag ) ;
}
2013-01-04 16:58:23 -08:00
vjs . insertFirst ( tag , el ) ; // Breaks iPhone, fixed in HTML5 setup.
2012-12-30 21:45:50 -08:00
return el ;
2013-01-10 13:06:12 -08:00
} ;
2012-12-30 21:45:50 -08:00
// /* Media Technology (tech)
// ================================================================================ */
// Load/Create an instance of playback technlogy including element and API methods
// And append playback element in player div.
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . loadTech = function ( techName , source ) {
2012-12-30 21:45:50 -08:00
// Pause and remove current playback technology
if ( this . tech ) {
this . unloadTech ( ) ;
// If the first time loading, HTML5 tag will exist but won't be initialized
// So we need to remove it if we're not loading HTML5
2013-01-10 13:06:12 -08:00
} else if ( techName !== 'Html5' && this . tag ) {
2012-12-30 21:45:50 -08:00
this . el _ . removeChild ( this . tag ) ;
this . tag = null ;
}
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
this . techName = techName ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Turn off API access because we're loading a new tech that might load asynchronously
this . isReady _ = false ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
var techReady = function ( ) {
2013-01-16 20:24:38 -05:00
this . player _ . triggerReady ( ) ;
2011-11-29 11:40:05 -08:00
2012-12-31 15:25:56 -08:00
// Manually track progress in cases where the browser/flash player doesn't report it.
2013-01-04 16:58:23 -08:00
if ( ! this . features . progressEvents ) {
2013-01-16 20:24:38 -05:00
this . player _ . manualProgressOn ( ) ;
2012-12-31 15:25:56 -08:00
}
2011-11-29 11:40:05 -08:00
2012-12-31 15:25:56 -08:00
// Manually track timeudpates in cases where the browser/flash player doesn't report it.
2013-01-04 16:58:23 -08:00
if ( ! this . features . timeupdateEvents ) {
2013-01-16 20:24:38 -05:00
this . player _ . manualTimeUpdatesOn ( ) ;
2012-12-31 15:25:56 -08:00
}
2013-01-10 13:06:12 -08:00
} ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Grab tech-specific options from player options and add source and parent element to use.
2013-01-10 13:06:12 -08:00
var techOptions = vjs . merge ( { source : source , parentEl : this . el _ } , this . options [ techName . toLowerCase ( ) ] ) ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
if ( source ) {
if ( source . src == this . cache _ . src && this . cache _ . currentTime > 0 ) {
2013-01-10 13:06:12 -08:00
techOptions [ 'startTime' ] = this . cache _ . currentTime ;
2011-11-29 11:40:05 -08:00
}
2012-04-25 15:15:33 -07:00
2012-12-30 21:45:50 -08:00
this . cache _ . src = source . src ;
}
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Initialize tech instance
2013-01-04 16:58:23 -08:00
this . tech = new window [ 'videojs' ] [ techName ] ( this , techOptions ) ;
2012-12-30 21:45:50 -08:00
this . tech . ready ( techReady ) ;
} ;
2013-01-10 13:06:12 -08:00
vjs . Player . prototype . unloadTech = function ( ) {
this . tech . dispose ( ) ;
2012-12-30 21:45:50 -08:00
2013-01-10 13:06:12 -08:00
// Turn off any manual progress or timeupdate tracking
if ( this . manualProgress ) { this . manualProgressOff ( ) ; }
2012-12-30 21:45:50 -08:00
2013-01-10 13:06:12 -08:00
if ( this . manualTimeUpdates ) { this . manualTimeUpdatesOff ( ) ; }
2012-12-30 21:45:50 -08:00
2013-01-10 13:06:12 -08:00
this . tech = false ;
} ;
2012-12-30 21:45:50 -08:00
// There's many issues around changing the size of a Flash (or other plugin) object.
// First is a plugin reload issue in Firefox that has been around for 11 years: https://bugzilla.mozilla.org/show_bug.cgi?id=90268
// Then with the new fullscreen API, Mozilla and webkit browsers will reload the flash object after going to fullscreen.
// To get around this, we're unloading the tech, caching source and currentTime values, and reloading the tech once the plugin is resized.
// reloadTech: function(betweenFn){
2013-01-10 13:06:12 -08:00
// vjs.log('unloadingTech')
2012-12-30 21:45:50 -08:00
// this.unloadTech();
2013-01-10 13:06:12 -08:00
// vjs.log('unloadedTech')
2012-12-30 21:45:50 -08:00
// if (betweenFn) { betweenFn.call(); }
2013-01-10 13:06:12 -08:00
// vjs.log('LoadingTech')
2012-12-30 21:45:50 -08:00
// this.loadTech(this.techName, { src: this.cache_.src })
2013-01-10 13:06:12 -08:00
// vjs.log('loadedTech')
2012-12-30 21:45:50 -08:00
// },
/ * F a l l b a c k s f o r u n s u p p o r t e d e v e n t t y p e s
2011-11-29 11:40:05 -08:00
=== === === === === === === === === === === === === === === === === === === === === === === === === === == * /
2012-12-30 21:45:50 -08:00
// Manually trigger progress events based on changes to the buffered amount
// Many flash players and older HTML5 browsers don't send progress or progress-like events
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . manualProgressOn = function ( ) {
2012-12-31 15:25:56 -08:00
this . manualProgress = true ;
2012-12-30 21:45:50 -08:00
2012-12-31 15:25:56 -08:00
// Trigger progress watching when a source begins loading
this . trackProgress ( ) ;
2012-12-30 21:45:50 -08:00
2012-12-31 15:25:56 -08:00
// Watch for a native progress event call on the tech element
// In HTML5, some older versions don't support the progress event
// So we're assuming they don't, and turning off manual progress if they do.
// As opposed to doing user agent detection
2013-01-10 13:06:12 -08:00
this . tech . one ( 'progress' , function ( ) {
2012-12-30 21:45:50 -08:00
2012-12-31 15:25:56 -08:00
// Update known progress support for this playback technology
2013-01-04 16:58:23 -08:00
this . features . progressEvents = true ;
2012-12-30 21:45:50 -08:00
2012-12-31 15:25:56 -08:00
// Turn off manual progress tracking
2013-01-16 20:24:38 -05:00
this . player _ . manualProgressOff ( ) ;
2012-12-31 15:25:56 -08:00
} ) ;
} ;
2012-12-30 21:45:50 -08:00
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . manualProgressOff = function ( ) {
2012-12-31 15:25:56 -08:00
this . manualProgress = false ;
this . stopTrackingProgress ( ) ;
} ;
2012-12-30 21:45:50 -08:00
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . trackProgress = function ( ) {
2012-12-30 21:45:50 -08:00
2013-01-04 16:58:23 -08:00
this . progressInterval = setInterval ( vjs . bind ( this , function ( ) {
2012-12-31 15:25:56 -08:00
// Don't trigger unless buffered amount is greater than last time
// log(this.cache_.bufferEnd, this.buffered().end(0), this.duration())
/* TODO: update for multiple buffered regions */
if ( this . cache _ . bufferEnd < this . buffered ( ) . end ( 0 ) ) {
2013-01-10 13:06:12 -08:00
this . trigger ( 'progress' ) ;
2012-12-31 15:25:56 -08:00
} else if ( this . bufferedPercent ( ) == 1 ) {
this . stopTrackingProgress ( ) ;
2013-01-10 13:06:12 -08:00
this . trigger ( 'progress' ) ; // Last update
2012-12-31 15:25:56 -08:00
}
} ) , 500 ) ;
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . stopTrackingProgress = function ( ) { clearInterval ( this . progressInterval ) ; } ;
2012-12-30 21:45:50 -08:00
2012-12-31 15:25:56 -08:00
/* Time Tracking -------------------------------------------------------------- */
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . manualTimeUpdatesOn = function ( ) {
2012-12-31 15:25:56 -08:00
this . manualTimeUpdates = true ;
2012-12-30 21:45:50 -08:00
2013-01-10 13:06:12 -08:00
this . on ( 'play' , this . trackCurrentTime ) ;
this . on ( 'pause' , this . stopTrackingCurrentTime ) ;
2012-12-31 15:25:56 -08:00
// timeupdate is also called by .currentTime whenever current time is set
2012-12-30 21:45:50 -08:00
2012-12-31 15:25:56 -08:00
// Watch for native timeupdate event
2013-01-10 13:06:12 -08:00
this . tech . one ( 'timeupdate' , function ( ) {
2012-12-31 15:25:56 -08:00
// Update known progress support for this playback technology
2013-01-04 16:58:23 -08:00
this . features . timeupdateEvents = true ;
2012-12-31 15:25:56 -08:00
// Turn off manual progress tracking
2013-01-16 20:24:38 -05:00
this . player _ . manualTimeUpdatesOff ( ) ;
2012-12-31 15:25:56 -08:00
} ) ;
} ;
2012-12-30 21:45:50 -08:00
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . manualTimeUpdatesOff = function ( ) {
2012-12-31 15:25:56 -08:00
this . manualTimeUpdates = false ;
this . stopTrackingCurrentTime ( ) ;
2013-01-10 13:06:12 -08:00
this . off ( 'play' , this . trackCurrentTime ) ;
this . off ( 'pause' , this . stopTrackingCurrentTime ) ;
2012-12-31 15:25:56 -08:00
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . trackCurrentTime = function ( ) {
2012-12-31 15:25:56 -08:00
if ( this . currentTimeInterval ) { this . stopTrackingCurrentTime ( ) ; }
2013-01-04 16:58:23 -08:00
this . currentTimeInterval = setInterval ( vjs . bind ( this , function ( ) {
2013-01-10 13:06:12 -08:00
this . trigger ( 'timeupdate' ) ;
2012-12-31 15:25:56 -08:00
} ) , 250 ) ; // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
} ;
// Turn off play progress tracking (when paused or dragging)
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . stopTrackingCurrentTime = function ( ) { clearInterval ( this . currentTimeInterval ) ; } ;
2012-12-30 21:45:50 -08:00
// /* Player event handlers (how the player reacts to certain events)
// ================================================================================ */
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . onEnded = function ( ) {
2013-01-10 13:06:12 -08:00
if ( this . options [ 'loop' ] ) {
2012-12-30 21:45:50 -08:00
this . currentTime ( 0 ) ;
this . play ( ) ;
}
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . onPlay = function ( ) {
2013-01-10 13:06:12 -08:00
vjs . removeClass ( this . el _ , 'vjs-paused' ) ;
vjs . addClass ( this . el _ , 'vjs-playing' ) ;
2012-12-30 21:45:50 -08:00
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . onPause = function ( ) {
2013-01-10 13:06:12 -08:00
vjs . removeClass ( this . el _ , 'vjs-playing' ) ;
vjs . addClass ( this . el _ , 'vjs-paused' ) ;
2012-12-30 21:45:50 -08:00
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . onProgress = function ( ) {
2012-12-30 21:45:50 -08:00
// Add custom event for when source is finished downloading.
if ( this . bufferedPercent ( ) == 1 ) {
2013-01-10 13:06:12 -08:00
this . trigger ( 'loadedalldata' ) ;
2012-12-30 21:45:50 -08:00
}
} ;
// Update duration with durationchange event
// Allows for cacheing value instead of asking player each time.
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . onDurationChange = function ( ) {
2013-01-10 13:06:12 -08:00
this . duration ( this . techGet ( 'duration' ) ) ;
2012-12-30 21:45:50 -08:00
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . onError = function ( e ) {
2013-01-10 13:06:12 -08:00
vjs . log ( 'Video Error' , e ) ;
2012-12-30 21:45:50 -08:00
} ;
// /* Player API
// ================================================================================ */
/ * *
* Object for cached values .
* @ private
* /
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . cache _ ;
2012-12-30 21:45:50 -08:00
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . getCache = function ( ) {
2012-12-30 21:45:50 -08:00
return this . cache _ ;
} ;
// Pass values to the playback tech
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . techCall = function ( method , arg ) {
2012-12-30 21:45:50 -08:00
// If it's not ready yet, call method when it is
2013-01-17 20:33:53 -05:00
if ( this . tech && this . tech . isReady _ ) {
2012-12-30 21:45:50 -08:00
this . tech . ready ( function ( ) {
this [ method ] ( arg ) ;
} ) ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Otherwise call method now
} else {
try {
this . tech [ method ] ( arg ) ;
} catch ( e ) {
2013-01-04 16:58:23 -08:00
vjs . log ( e ) ;
2012-02-02 19:16:45 -08:00
}
2012-12-30 21:45:50 -08:00
}
} ;
2012-02-02 19:16:45 -08:00
2012-12-30 21:45:50 -08:00
// Get calls can't wait for the tech, and sometimes don't need to.
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . techGet = function ( method ) {
2012-02-03 10:28:00 -08:00
2013-01-17 20:33:53 -05:00
// Make sure there is a tech
// if (!this.tech) {
// return;
// }
2012-12-30 21:45:50 -08:00
if ( this . tech . isReady _ ) {
2012-02-03 10:28:00 -08:00
2012-12-30 21:45:50 -08:00
// Flash likes to die and reload when you hide or reposition it.
// In these cases the object methods go away and we get errors.
// When that happens we'll catch the errors and inform tech that it's not ready any more.
try {
return this . tech [ method ] ( ) ;
} catch ( e ) {
2012-02-03 10:28:00 -08:00
2012-12-30 21:45:50 -08:00
// When building additional tech libs, an expected method may not be defined yet
if ( this . tech [ method ] === undefined ) {
2013-01-10 13:06:12 -08:00
vjs . log ( 'Video.js: ' + method + ' method not defined for ' + this . techName + ' playback technology.' , e ) ;
2012-02-03 10:28:00 -08:00
2012-12-30 21:45:50 -08:00
} else {
2012-02-03 10:28:00 -08:00
2012-12-30 21:45:50 -08:00
// When a method isn't available on the object it throws a TypeError
2013-01-10 13:06:12 -08:00
if ( e . name == 'TypeError' ) {
vjs . log ( 'Video.js: ' + method + ' unavailable on ' + this . techName + ' playback technology element.' , e ) ;
2012-12-30 21:45:50 -08:00
this . tech . isReady _ = false ;
2012-12-31 15:25:56 -08:00
throw e ;
2012-12-30 21:45:50 -08:00
} else {
2013-01-04 16:58:23 -08:00
vjs . log ( e ) ;
2012-02-03 10:28:00 -08:00
}
}
2011-11-29 11:40:05 -08:00
}
2012-12-30 21:45:50 -08:00
}
2012-02-03 10:28:00 -08:00
2012-12-30 21:45:50 -08:00
return ;
} ;
2011-11-29 11:40:05 -08:00
2013-01-17 20:33:53 -05:00
/ * *
* Start media playback
* http : //dev.w3.org/html5/spec/video.html#dom-media-play
* We 're triggering the ' play ' event here instead of relying on the
* media element to allow using event . preventDefault ( ) to stop
* play from happening if desired . Usecase : preroll ads .
* /
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . play = function ( ) {
2013-01-17 20:33:53 -05:00
// Create an event object so we can check for preventDefault after
var e = { type : 'play' , target : this . el _ } ;
this . trigger ( e ) ;
if ( ! e . isDefaultPrevented ( ) ) {
this . techCall ( 'play' ) ;
}
2012-12-30 21:45:50 -08:00
return this ;
} ;
2011-12-05 11:28:18 -08:00
2012-12-30 21:45:50 -08:00
// http://dev.w3.org/html5/spec/video.html#dom-media-pause
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . pause = function ( ) {
2013-01-10 13:06:12 -08:00
this . techCall ( 'pause' ) ;
2012-12-30 21:45:50 -08:00
return this ;
} ;
2011-12-05 11:28:18 -08:00
2012-12-30 21:45:50 -08:00
// http://dev.w3.org/html5/spec/video.html#dom-media-paused
// The initial state of paused should be true (in Safari it's actually false)
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . paused = function ( ) {
2013-01-10 13:06:12 -08:00
return ( this . techGet ( 'paused' ) === false ) ? false : true ;
2012-12-30 21:45:50 -08:00
} ;
2012-02-02 14:56:47 -08:00
2012-12-30 21:45:50 -08:00
// http://dev.w3.org/html5/spec/video.html#dom-media-currenttime
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . currentTime = function ( seconds ) {
2012-12-30 21:45:50 -08:00
if ( seconds !== undefined ) {
2011-12-05 11:28:18 -08:00
2012-12-30 21:45:50 -08:00
// Cache the last set value for smoother scrubbing.
this . cache _ . lastSetCurrentTime = seconds ;
2012-01-05 23:25:09 -08:00
2013-01-10 13:06:12 -08:00
this . techCall ( 'setCurrentTime' , seconds ) ;
2012-02-02 14:56:47 -08:00
2012-12-30 21:45:50 -08:00
// Improve the accuracy of manual timeupdates
2013-01-10 13:06:12 -08:00
if ( this . manualTimeUpdates ) { this . trigger ( 'timeupdate' ) ; }
2012-04-25 15:15:33 -07:00
2012-12-30 21:45:50 -08:00
return this ;
}
2012-04-25 15:15:33 -07:00
2012-12-30 21:45:50 -08:00
// Cache last currentTime and return
// Default to 0 seconds
2013-01-10 13:06:12 -08:00
return this . cache _ . currentTime = ( this . techGet ( 'currentTime' ) || 0 ) ;
2012-12-30 21:45:50 -08:00
} ;
2012-04-25 15:15:33 -07:00
2012-12-30 21:45:50 -08:00
// http://dev.w3.org/html5/spec/video.html#dom-media-duration
// Duration should return NaN if not available. ParseFloat will turn false-ish values to NaN.
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . duration = function ( seconds ) {
2012-12-30 21:45:50 -08:00
if ( seconds !== undefined ) {
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Cache the last set value for optimiized scrubbing (esp. Flash)
this . cache _ . duration = parseFloat ( seconds ) ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
return this ;
}
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
return this . cache _ . duration ;
} ;
// Calculates how much time is left. Not in spec, but useful.
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . remainingTime = function ( ) {
2012-12-30 21:45:50 -08:00
return this . duration ( ) - this . currentTime ( ) ;
} ;
// http://dev.w3.org/html5/spec/video.html#dom-media-buffered
2013-01-10 13:06:12 -08:00
// Buffered returns a timerange object.
// Kind of like an array of portions of the video that have been downloaded.
2012-12-30 21:45:50 -08:00
// So far no browsers return more than one range (portion)
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . buffered = function ( ) {
2013-01-10 13:06:12 -08:00
var buffered = this . techGet ( 'buffered' ) ,
2012-12-30 21:45:50 -08:00
start = 0 ,
2013-01-10 13:06:12 -08:00
// Default end to 0 and store in values
end = this . cache _ . bufferEnd = this . cache _ . bufferEnd || 0 ;
2012-12-30 21:45:50 -08:00
if ( buffered && buffered . length > 0 && buffered . end ( 0 ) !== end ) {
end = buffered . end ( 0 ) ;
// Storing values allows them be overridden by setBufferedFromProgress
this . cache _ . bufferEnd = end ;
}
2012-02-02 14:56:47 -08:00
2013-01-04 16:58:23 -08:00
return vjs . createTimeRange ( start , end ) ;
2012-12-30 21:45:50 -08:00
} ;
2012-02-02 14:56:47 -08:00
2012-12-30 21:45:50 -08:00
// Calculates amount of buffer is full. Not in spec but useful.
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . bufferedPercent = function ( ) {
2012-12-30 21:45:50 -08:00
return ( this . duration ( ) ) ? this . buffered ( ) . end ( 0 ) / this . duration ( ) : 0 ;
} ;
2012-02-02 14:56:47 -08:00
2012-12-30 21:45:50 -08:00
// http://dev.w3.org/html5/spec/video.html#dom-media-volume
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . volume = function ( percentAsDecimal ) {
2012-12-30 21:45:50 -08:00
var vol ;
2012-04-09 14:53:03 -07:00
2012-12-30 21:45:50 -08:00
if ( percentAsDecimal !== undefined ) {
vol = Math . max ( 0 , Math . min ( 1 , parseFloat ( percentAsDecimal ) ) ) ; // Force value to between 0 and 1
this . cache _ . volume = vol ;
2013-01-10 13:06:12 -08:00
this . techCall ( 'setVolume' , vol ) ;
vjs . setLocalStorage ( 'volume' , vol ) ;
2012-12-30 21:45:50 -08:00
return this ;
}
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Default to 1 when returning current volume.
2013-01-10 13:06:12 -08:00
vol = parseFloat ( this . techGet ( 'volume' ) ) ;
2012-12-30 21:45:50 -08:00
return ( isNaN ( vol ) ) ? 1 : vol ;
} ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// http://dev.w3.org/html5/spec/video.html#attr-media-muted
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . muted = function ( muted ) {
2012-12-30 21:45:50 -08:00
if ( muted !== undefined ) {
2013-01-10 13:06:12 -08:00
this . techCall ( 'setMuted' , muted ) ;
2012-12-30 21:45:50 -08:00
return this ;
}
2013-01-10 13:06:12 -08:00
return this . techGet ( 'muted' ) || false ; // Default to false
2012-12-30 21:45:50 -08:00
} ;
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
// Check if current tech can support native fullscreen (e.g. with built in controls lik iOS, so not our flash swf)
2013-01-10 13:06:12 -08:00
vjs . Player . prototype . supportsFullScreen = function ( ) { return this . techGet ( 'supportsFullScreen' ) || false ; } ;
2012-01-29 20:03:44 -08:00
2012-12-30 21:45:50 -08:00
// Turn on fullscreen (or window) mode
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . requestFullScreen = function ( ) {
var requestFullScreen = vjs . support . requestFullScreen ;
2012-01-29 20:03:44 -08:00
2012-12-30 21:45:50 -08:00
this . isFullScreen = true ;
2012-02-13 17:51:52 -08:00
2012-12-30 21:45:50 -08:00
// Check for browser element fullscreen support
if ( requestFullScreen ) {
2012-02-13 17:51:52 -08:00
2012-12-30 21:45:50 -08:00
// Trigger fullscreenchange event after change
2013-01-04 16:58:23 -08:00
vjs . on ( document , requestFullScreen . eventName , vjs . bind ( this , function ( ) {
2012-12-30 21:45:50 -08:00
this . isFullScreen = document [ requestFullScreen . isFullScreen ] ;
2012-02-13 17:51:52 -08:00
2012-12-30 21:45:50 -08:00
// If cancelling fullscreen, remove event listener.
2013-01-10 13:06:12 -08:00
if ( this . isFullScreen === false ) {
2013-01-04 16:58:23 -08:00
vjs . off ( document , requestFullScreen . eventName , arguments . callee ) ;
2012-12-30 21:45:50 -08:00
}
2012-01-05 23:25:09 -08:00
2013-01-10 13:06:12 -08:00
this . trigger ( 'fullscreenchange' ) ;
2012-12-30 21:45:50 -08:00
} ) ) ;
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
// Flash and other plugins get reloaded when you take their parent to fullscreen.
// To fix that we'll remove the tech, and reload it after the resize has finished.
2013-01-10 13:06:12 -08:00
if ( this . tech . features . fullscreenResize === false && this . options [ 'flash' ] [ 'iFrameMode' ] !== true ) {
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
this . pause ( ) ;
this . unloadTech ( ) ;
2012-01-05 23:25:09 -08:00
2013-01-04 16:58:23 -08:00
vjs . on ( document , requestFullScreen . eventName , vjs . bind ( this , function ( ) {
vjs . off ( document , requestFullScreen . eventName , arguments . callee ) ;
2012-12-30 21:45:50 -08:00
this . loadTech ( this . techName , { src : this . cache _ . src } ) ;
} ) ) ;
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
this . el _ [ requestFullScreen . requestFn ] ( ) ;
2012-01-05 23:25:09 -08:00
} else {
2012-12-30 21:45:50 -08:00
this . el _ [ requestFullScreen . requestFn ] ( ) ;
2012-01-05 23:25:09 -08:00
}
2012-12-30 21:45:50 -08:00
} else if ( this . tech . supportsFullScreen ( ) ) {
2013-01-10 13:06:12 -08:00
this . trigger ( 'fullscreenchange' ) ;
this . techCall ( 'enterFullScreen' ) ;
2011-12-01 15:24:34 -08:00
2012-12-30 21:45:50 -08:00
} else {
2013-01-10 13:06:12 -08:00
this . trigger ( 'fullscreenchange' ) ;
2012-12-30 21:45:50 -08:00
this . enterFullWindow ( ) ;
}
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
return this ;
} ;
2012-02-13 17:42:22 -08:00
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . cancelFullScreen = function ( ) {
var requestFullScreen = vjs . support . requestFullScreen ;
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
this . isFullScreen = false ;
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
// Check for browser element fullscreen support
if ( requestFullScreen ) {
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
// Flash and other plugins get reloaded when you take their parent to fullscreen.
// To fix that we'll remove the tech, and reload it after the resize has finished.
2013-01-10 13:06:12 -08:00
if ( this . tech . features . fullscreenResize === false && this . options [ 'flash' ] [ 'iFrameMode' ] !== true ) {
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
this . pause ( ) ;
this . unloadTech ( ) ;
2012-01-05 23:25:09 -08:00
2013-01-04 16:58:23 -08:00
vjs . on ( document , requestFullScreen . eventName , vjs . bind ( this , function ( ) {
vjs . off ( document , requestFullScreen . eventName , arguments . callee ) ;
2013-01-10 13:06:12 -08:00
this . loadTech ( this . techName , { src : this . cache _ . src } ) ;
2012-12-30 21:45:50 -08:00
} ) ) ;
2011-12-01 16:48:06 -08:00
2012-12-30 21:45:50 -08:00
document [ requestFullScreen . cancelFn ] ( ) ;
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
} else {
document [ requestFullScreen . cancelFn ] ( ) ;
}
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
} else if ( this . tech . supportsFullScreen ( ) ) {
2013-01-10 13:06:12 -08:00
this . techCall ( 'exitFullScreen' ) ;
this . trigger ( 'fullscreenchange' ) ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
} else {
this . exitFullWindow ( ) ;
2013-01-10 13:06:12 -08:00
this . trigger ( 'fullscreenchange' ) ;
2012-12-30 21:45:50 -08:00
}
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
return this ;
} ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// When fullscreen isn't supported we can stretch the video container to as wide as the browser will let us.
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . enterFullWindow = function ( ) {
2012-12-30 21:45:50 -08:00
this . isFullWindow = true ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Storing original doc overflow value to return to when fullscreen is off
this . docOrigOverflow = document . documentElement . style . overflow ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Add listener for esc key to exit fullscreen
2013-01-10 13:06:12 -08:00
vjs . on ( document , 'keydown' , vjs . bind ( this , this . fullWindowOnEscKey ) ) ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Hide any scroll bars
document . documentElement . style . overflow = 'hidden' ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Apply fullscreen styles
2013-01-10 13:06:12 -08:00
vjs . addClass ( document . body , 'vjs-full-window' ) ;
vjs . addClass ( this . el _ , 'vjs-fullscreen' ) ;
2011-11-29 11:40:05 -08:00
2013-01-10 13:06:12 -08:00
this . trigger ( 'enterFullWindow' ) ;
2012-12-30 21:45:50 -08:00
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . fullWindowOnEscKey = function ( event ) {
2013-01-10 13:06:12 -08:00
if ( event . keyCode === 27 ) {
if ( this . isFullScreen === true ) {
2012-12-30 21:45:50 -08:00
this . cancelFullScreen ( ) ;
} else {
this . exitFullWindow ( ) ;
}
}
} ;
2011-11-29 11:40:05 -08:00
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . exitFullWindow = function ( ) {
2012-12-30 21:45:50 -08:00
this . isFullWindow = false ;
2013-01-10 13:06:12 -08:00
vjs . off ( document , 'keydown' , this . fullWindowOnEscKey ) ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Unhide scroll bars.
document . documentElement . style . overflow = this . docOrigOverflow ;
2011-11-29 11:40:05 -08:00
2012-12-30 21:45:50 -08:00
// Remove fullscreen styles
2013-01-10 13:06:12 -08:00
vjs . removeClass ( document . body , 'vjs-full-window' ) ;
vjs . removeClass ( this . el _ , 'vjs-fullscreen' ) ;
2012-02-02 14:56:47 -08:00
2012-12-30 21:45:50 -08:00
// Resize the box, controller, and poster to original sizes
// this.positionAll();
2013-01-10 13:06:12 -08:00
this . trigger ( 'exitFullWindow' ) ;
2012-12-30 21:45:50 -08:00
} ;
2012-02-02 14:56:47 -08:00
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . selectSource = function ( sources ) {
2012-02-02 14:56:47 -08:00
2012-12-30 21:45:50 -08:00
// Loop through each playback technology in the options order
2013-01-04 16:58:23 -08:00
for ( var i = 0 , j = this . options [ 'techOrder' ] ; i < j . length ; i ++ ) {
var techName = vjs . capitalize ( j [ i ] ) ,
tech = window [ 'videojs' ] [ techName ] ;
2012-02-02 14:56:47 -08:00
2012-12-30 21:45:50 -08:00
// Check if the browser supports this technology
2012-12-31 15:25:56 -08:00
if ( tech . isSupported ( ) ) {
2012-12-30 21:45:50 -08:00
// Loop through each source object
for ( var a = 0 , b = sources ; a < b . length ; a ++ ) {
var source = b [ a ] ;
2012-02-02 14:56:47 -08:00
2012-12-30 21:45:50 -08:00
// Check if source can be played with this technology
2012-12-31 15:25:56 -08:00
if ( tech [ 'canPlaySource' ] ( source ) ) {
2012-12-30 21:45:50 -08:00
return { source : source , tech : techName } ;
2012-02-02 14:56:47 -08:00
}
}
}
2012-12-30 21:45:50 -08:00
}
2012-02-02 14:56:47 -08:00
2012-12-30 21:45:50 -08:00
return false ;
} ;
// src is a pretty powerful function
// If you pass it an array of source objects, it will find the best source to play and use that object.src
// If the new source requires a new playback technology, it will switch to that.
// If you pass it an object, it will set the source to object.src
// If you pass it anything else (url string) it will set the video source to that
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . src = function ( source ) {
2012-12-30 21:45:50 -08:00
// Case: Array of source objects to choose from and pick the best to play
if ( source instanceof Array ) {
var sourceTech = this . selectSource ( source ) ,
techName ;
if ( sourceTech ) {
source = sourceTech . source ;
techName = sourceTech . tech ;
// If this technology is already loaded, set source
if ( techName == this . techName ) {
this . src ( source ) ; // Passing the source object
// Otherwise load this technology with chosen source
2012-02-02 14:56:47 -08:00
} else {
2012-12-30 21:45:50 -08:00
this . loadTech ( techName , source ) ;
2011-11-29 11:40:05 -08:00
}
2012-12-30 21:45:50 -08:00
} else {
2013-01-10 13:48:41 -08:00
this . el _ . appendChild ( vjs . createEl ( 'p' , {
innerHTML : 'Sorry, no compatible source and playback technology were found for this video. Try using another browser like <a href="http://www.google.com/chrome">Google Chrome</a> or download the latest <a href="http://get.adobe.com/flashplayer/">Adobe Flash Player</a>.'
} ) ) ;
2012-12-30 21:45:50 -08:00
}
2011-11-29 11:40:05 -08:00
2013-01-10 13:06:12 -08:00
// Case: Source object { src: '', type: '' ... }
2012-12-30 21:45:50 -08:00
} else if ( source instanceof Object ) {
2012-02-02 14:56:47 -08:00
2013-01-04 16:58:23 -08:00
if ( window [ 'videojs' ] [ this . techName ] [ 'canPlaySource' ] ( source ) ) {
2012-12-30 21:45:50 -08:00
this . src ( source . src ) ;
2011-11-29 11:40:05 -08:00
} else {
2012-12-30 21:45:50 -08:00
// Send through tech loop to check for a compatible technology.
this . src ( [ source ] ) ;
}
2012-01-05 23:25:09 -08:00
2012-12-30 21:45:50 -08:00
// Case: URL String (http://myvideo...)
} else {
// Cache for getting last set source
this . cache _ . src = source ;
if ( ! this . isReady _ ) {
this . ready ( function ( ) {
this . src ( source ) ;
} ) ;
} else {
2013-01-10 13:06:12 -08:00
this . techCall ( 'src' , source ) ;
if ( this . options [ 'preload' ] == 'auto' ) {
2012-12-30 21:45:50 -08:00
this . load ( ) ;
}
2013-01-10 13:06:12 -08:00
if ( this . options [ 'autoplay' ] ) {
2012-12-30 21:45:50 -08:00
this . play ( ) ;
2011-12-01 15:47:12 -08:00
}
2011-11-29 11:40:05 -08:00
}
2012-12-30 21:45:50 -08:00
}
return this ;
} ;
// Begin loading the src data
// http://dev.w3.org/html5/spec/video.html#dom-media-load
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . load = function ( ) {
2013-01-10 13:06:12 -08:00
this . techCall ( 'load' ) ;
2012-12-30 21:45:50 -08:00
return this ;
} ;
// http://dev.w3.org/html5/spec/video.html#dom-media-currentsrc
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . currentSrc = function ( ) {
2013-01-10 13:06:12 -08:00
return this . techGet ( 'currentSrc' ) || this . cache _ . src || '' ;
2012-12-30 21:45:50 -08:00
} ;
// Attributes/Options
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . preload = function ( value ) {
2012-12-30 21:45:50 -08:00
if ( value !== undefined ) {
2013-01-10 13:06:12 -08:00
this . techCall ( 'setPreload' , value ) ;
this . options [ 'preload' ] = value ;
2011-11-29 11:40:05 -08:00
return this ;
2012-12-30 21:45:50 -08:00
}
2013-01-10 13:06:12 -08:00
return this . techGet ( 'preload' ) ;
2012-12-30 21:45:50 -08:00
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . autoplay = function ( value ) {
2012-12-30 21:45:50 -08:00
if ( value !== undefined ) {
2013-01-10 13:06:12 -08:00
this . techCall ( 'setAutoplay' , value ) ;
this . options [ 'autoplay' ] = value ;
2011-11-29 11:40:05 -08:00
return this ;
2012-12-30 21:45:50 -08:00
}
2013-01-10 13:06:12 -08:00
return this . techGet ( 'autoplay' , value ) ;
2012-12-30 21:45:50 -08:00
} ;
2013-01-04 16:58:23 -08:00
vjs . Player . prototype . loop = function ( value ) {
2012-12-30 21:45:50 -08:00
if ( value !== undefined ) {
2013-01-10 13:06:12 -08:00
this . techCall ( 'setLoop' , value ) ;
this . options [ 'loop' ] = value ;
2012-12-30 21:45:50 -08:00
return this ;
}
2013-01-10 13:06:12 -08:00
return this . techGet ( 'loop' ) ;
2012-12-30 21:45:50 -08:00
} ;
2013-01-10 13:06:12 -08:00
vjs . Player . prototype . controls = function ( ) { return this . options [ 'controls' ] ; } ;
vjs . Player . prototype . poster = function ( ) { return this . techGet ( 'poster' ) ; } ;
vjs . Player . prototype . error = function ( ) { return this . techGet ( 'error' ) ; } ;
vjs . Player . prototype . ended = function ( ) { return this . techGet ( 'ended' ) ; } ;
2012-12-30 21:45:50 -08:00
// Methods to add support for
2013-01-10 13:06:12 -08:00
// networkState: function(){ return this.techCall('networkState'); },
// readyState: function(){ return this.techCall('readyState'); },
// seeking: function(){ return this.techCall('seeking'); },
// initialTime: function(){ return this.techCall('initialTime'); },
// startOffsetTime: function(){ return this.techCall('startOffsetTime'); },
// played: function(){ return this.techCall('played'); },
// seekable: function(){ return this.techCall('seekable'); },
// videoTracks: function(){ return this.techCall('videoTracks'); },
// audioTracks: function(){ return this.techCall('audioTracks'); },
// videoWidth: function(){ return this.techCall('videoWidth'); },
// videoHeight: function(){ return this.techCall('videoHeight'); },
// defaultPlaybackRate: function(){ return this.techCall('defaultPlaybackRate'); },
// playbackRate: function(){ return this.techCall('playbackRate'); },
// mediaGroup: function(){ return this.techCall('mediaGroup'); },
// controller: function(){ return this.techCall('controller'); },
// defaultMuted: function(){ return this.techCall('defaultMuted'); }
2012-12-30 21:45:50 -08:00
// TODO
// currentSrcList: the array of sources including other formats and bitrates
// playList: array of source lists in order of playback
2011-11-29 11:40:05 -08:00
2012-01-05 23:25:09 -08:00
// RequestFullscreen API
( function ( ) {
2013-01-10 13:06:12 -08:00
var requestFn , cancelFn , eventName , isFullScreen ;
2012-01-05 23:25:09 -08:00
// Current W3C Spec
// http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html#api
// Mozilla Draft: https://wiki.mozilla.org/Gecko:FullScreenAPI#fullscreenchange_event
if ( document . cancelFullscreen !== undefined ) {
2013-01-10 13:06:12 -08:00
requestFn = 'requestFullscreen' ;
cancelFn = 'exitFullscreen' ;
eventName = 'fullscreenchange' ;
isFullScreen = 'fullScreen' ;
2012-01-05 23:25:09 -08:00
// Webkit (Chrome/Safari) and Mozilla (Firefox) have working implementaitons
// that use prefixes and vary slightly from the new W3C spec. Specifically, using 'exit' instead of 'cancel',
// and lowercasing the 'S' in Fullscreen.
// Other browsers don't have any hints of which version they might follow yet, so not going to try to predict by loopeing through all prefixes.
} else {
2013-01-10 13:06:12 -08:00
var prefixes = [ 'moz' , 'webkit' ] ;
2012-12-30 21:45:50 -08:00
for ( var i = prefixes . length - 1 ; i >= 0 ; i -- ) {
2013-01-10 13:06:12 -08:00
var prefix = prefixes [ i ] ;
2012-01-05 23:25:09 -08:00
2012-01-16 15:03:38 -08:00
// https://github.com/zencoder/video-js/pull/128
2013-01-10 13:06:12 -08:00
if ( ( prefix != 'moz' || document . mozFullScreenEnabled ) && document [ prefix + 'CancelFullScreen' ] !== undefined ) {
requestFn = prefix + 'RequestFullScreen' ;
cancelFn = prefix + 'CancelFullScreen' ;
eventName = prefix + 'fullscreenchange' ;
2012-01-29 20:03:44 -08:00
2013-01-10 13:06:12 -08:00
if ( prefix == 'webkit' ) {
isFullScreen = prefix + 'IsFullScreen' ;
2012-01-29 20:03:44 -08:00
} else {
2013-01-10 13:06:12 -08:00
isFullScreen = prefix + 'FullScreen' ;
2012-01-29 20:03:44 -08:00
}
2012-01-05 23:25:09 -08:00
}
2013-01-10 13:06:12 -08:00
}
2012-01-05 23:25:09 -08:00
}
if ( requestFn ) {
2013-01-04 16:58:23 -08:00
vjs . support . requestFullScreen = {
2012-01-05 23:25:09 -08:00
requestFn : requestFn ,
cancelFn : cancelFn ,
2012-01-29 20:03:44 -08:00
eventName : eventName ,
isFullScreen : isFullScreen
2012-01-05 23:25:09 -08:00
} ;
}
2012-05-25 11:59:53 +02:00
} ) ( ) ;
2012-12-30 21:45:50 -08:00
/ * *
* @ constructor
* /
2013-01-04 16:58:23 -08:00
vjs . MediaLoader = function ( player , options , ready ) {
vjs . Component . call ( this , player , options , ready ) ;
2012-12-30 21:45:50 -08:00
// If there are no sources when the player is initialized,
// load the first supported playback technology.
2013-01-10 13:06:12 -08:00
if ( ! player . options [ 'sources' ] || player . options [ 'sources' ] . length === 0 ) {
2013-01-04 16:58:23 -08:00
for ( var i = 0 , j = player . options [ 'techOrder' ] ; i < j . length ; i ++ ) {
var techName = vjs . capitalize ( j [ i ] ) ,
tech = window [ 'videojs' ] [ techName ] ;
2012-12-30 21:45:50 -08:00
// Check if the browser supports this technology
2012-12-31 15:25:56 -08:00
if ( tech && tech . isSupported ( ) ) {
2012-12-30 21:45:50 -08:00
player . loadTech ( techName ) ;
break ;
}
}
} else {
// // Loop through playback technologies (HTML5, Flash) and check for support.
// // Then load the best source.
// // A few assumptions here:
// // All playback technologies respect preload false.
2013-01-10 13:06:12 -08:00
player . src ( player . options [ 'sources' ] ) ;
2012-12-30 21:45:50 -08:00
}
} ;
2013-01-04 16:58:23 -08:00
goog . inherits ( vjs . MediaLoader , vjs . Component ) ;
2012-12-30 21:45:50 -08:00