videojs_rails 4.10.2 → 4.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/videojs_rails/version.rb +1 -1
- data/vendor/assets/javascripts/video.js.erb +641 -258
- data/vendor/assets/stylesheets/video-js.css.erb +4 -4
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5859566b78fa09a28ae4f320dec8a8de7038789
|
4
|
+
data.tar.gz: 42f18794f2a096da9166824bbc587f90ab1f275c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f59b5364c73a63688a826865b6eb46edabe5dfe9a1fda58a077a8677075caf110308d837847a65f8f08a086d563cae51858a13589d7e9dd200bf65433f71b260
|
7
|
+
data.tar.gz: b327fb577882debbafb08b67c6248fe50c18f7618b492516961a63620bdbdde2077d0713c6ded92b0c6cbda93b5e5af83905b37250f29634242f3be57f0f7477
|
@@ -63,7 +63,7 @@ var vjs = function(id, options, ready){
|
|
63
63
|
var videojs = window['videojs'] = vjs;
|
64
64
|
|
65
65
|
// CDN Version. Used to target right flash swf.
|
66
|
-
vjs.CDN_VERSION = '4.
|
66
|
+
vjs.CDN_VERSION = '4.11';
|
67
67
|
vjs.ACCESS_PROTOCOL = ('https:' == document.location.protocol ? 'https://' : 'http://');
|
68
68
|
|
69
69
|
/**
|
@@ -116,7 +116,7 @@ vjs.options = {
|
|
116
116
|
};
|
117
117
|
|
118
118
|
// Set CDN Version of swf
|
119
|
-
// The added (+) blocks the replace from changing this 4.
|
119
|
+
// The added (+) blocks the replace from changing this 4.11 string
|
120
120
|
if (vjs.CDN_VERSION !== 'GENERATED'+'_CDN_VSN') {
|
121
121
|
videojs.options['flash']['swf'] = "<%= asset_path('video-js.swf') %>";
|
122
122
|
}
|
@@ -161,7 +161,7 @@ if (typeof define === 'function' && define['amd']) {
|
|
161
161
|
module['exports'] = videojs;
|
162
162
|
}
|
163
163
|
/**
|
164
|
-
* Core Object/Class for objects that use inheritance +
|
164
|
+
* Core Object/Class for objects that use inheritance + constructors
|
165
165
|
*
|
166
166
|
* To create a class that can be subclassed itself, extend the CoreObject class.
|
167
167
|
*
|
@@ -214,7 +214,7 @@ if (typeof define === 'function' && define['amd']) {
|
|
214
214
|
vjs.CoreObject = vjs['CoreObject'] = function(){};
|
215
215
|
// Manually exporting vjs['CoreObject'] here for Closure Compiler
|
216
216
|
// because of the use of the extend/create class methods
|
217
|
-
// If we didn't do this, those functions would get
|
217
|
+
// If we didn't do this, those functions would get flattened to something like
|
218
218
|
// `a = ...` and `this.prototype` would refer to the global object instead of
|
219
219
|
// CoreObject
|
220
220
|
|
@@ -240,10 +240,10 @@ vjs.CoreObject.extend = function(props){
|
|
240
240
|
// In Resig's simple class inheritance (previously used) the constructor
|
241
241
|
// is a function that calls `this.init.apply(arguments)`
|
242
242
|
// However that would prevent us from using `ParentObject.call(this);`
|
243
|
-
// in a Child
|
244
|
-
// would still refer to the Child and cause an
|
243
|
+
// in a Child constructor because the `this` in `this.init`
|
244
|
+
// would still refer to the Child and cause an infinite loop.
|
245
245
|
// We would instead have to do
|
246
|
-
// `ParentObject.prototype.init.apply(this,
|
246
|
+
// `ParentObject.prototype.init.apply(this, arguments);`
|
247
247
|
// Bleh. We're not creating a _super() function, so it's good to keep
|
248
248
|
// the parent constructor reference simple.
|
249
249
|
subObj = function(){
|
@@ -272,7 +272,7 @@ vjs.CoreObject.extend = function(props){
|
|
272
272
|
};
|
273
273
|
|
274
274
|
/**
|
275
|
-
* Create a new
|
275
|
+
* Create a new instance of this Object class
|
276
276
|
*
|
277
277
|
* var myAnimal = Animal.create();
|
278
278
|
*
|
@@ -616,7 +616,7 @@ vjs.trigger = function(elem, event) {
|
|
616
616
|
* We've since updated to the latest version, but keeping this around
|
617
617
|
* for now just in case.
|
618
618
|
*/
|
619
|
-
// // Added in
|
619
|
+
// // Added in addition to book. Book code was broke.
|
620
620
|
// event = typeof event === 'object' ?
|
621
621
|
// event[vjs.expando] ?
|
622
622
|
// event :
|
@@ -785,7 +785,7 @@ vjs.obj.merge = function(obj1, obj2){
|
|
785
785
|
vjs.obj.deepMerge = function(obj1, obj2){
|
786
786
|
var key, val1, val2;
|
787
787
|
|
788
|
-
// make a copy of obj1 so we're not
|
788
|
+
// make a copy of obj1 so we're not overwriting original values.
|
789
789
|
// like prototype.options_ and all sub options objects
|
790
790
|
obj1 = vjs.obj.copy(obj1);
|
791
791
|
|
@@ -881,7 +881,7 @@ vjs.bind = function(context, fn, uid) {
|
|
881
881
|
|
882
882
|
/**
|
883
883
|
* Element Data Store. Allows for binding data to an element without putting it directly on the element.
|
884
|
-
* Ex. Event
|
884
|
+
* Ex. Event listeners are stored here.
|
885
885
|
* (also from jsninja.com, slightly modified and updated for closure compiler)
|
886
886
|
* @type {Object}
|
887
887
|
* @private
|
@@ -1100,7 +1100,7 @@ vjs.setElementAttributes = function(el, attributes){
|
|
1100
1100
|
|
1101
1101
|
/**
|
1102
1102
|
* Get an element's attribute values, as defined on the HTML tag
|
1103
|
-
*
|
1103
|
+
* Attributes are not the same as properties. They're defined on the tag
|
1104
1104
|
* or with setAttribute (which shouldn't be used with HTML)
|
1105
1105
|
* This will return true or false for boolean attributes.
|
1106
1106
|
* @param {Element} tag Element from which to get tag attributes
|
@@ -1283,87 +1283,7 @@ vjs.createTimeRange = function(start, end){
|
|
1283
1283
|
};
|
1284
1284
|
|
1285
1285
|
/**
|
1286
|
-
*
|
1287
|
-
* @param {String} url URL of resource
|
1288
|
-
* @param {Function} onSuccess Success callback
|
1289
|
-
* @param {Function=} onError Error callback
|
1290
|
-
* @param {Boolean=} withCredentials Flag which allow credentials
|
1291
|
-
* @private
|
1292
|
-
*/
|
1293
|
-
vjs.get = function(url, onSuccess, onError, withCredentials){
|
1294
|
-
var fileUrl, request, urlInfo, winLoc, crossOrigin;
|
1295
|
-
|
1296
|
-
onError = onError || function(){};
|
1297
|
-
|
1298
|
-
if (typeof XMLHttpRequest === 'undefined') {
|
1299
|
-
// Shim XMLHttpRequest for older IEs
|
1300
|
-
window.XMLHttpRequest = function () {
|
1301
|
-
try { return new window.ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch (e) {}
|
1302
|
-
try { return new window.ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch (f) {}
|
1303
|
-
try { return new window.ActiveXObject('Msxml2.XMLHTTP'); } catch (g) {}
|
1304
|
-
throw new Error('This browser does not support XMLHttpRequest.');
|
1305
|
-
};
|
1306
|
-
}
|
1307
|
-
|
1308
|
-
request = new XMLHttpRequest();
|
1309
|
-
|
1310
|
-
urlInfo = vjs.parseUrl(url);
|
1311
|
-
winLoc = window.location;
|
1312
|
-
// check if url is for another domain/origin
|
1313
|
-
// ie8 doesn't know location.origin, so we won't rely on it here
|
1314
|
-
crossOrigin = (urlInfo.protocol + urlInfo.host) !== (winLoc.protocol + winLoc.host);
|
1315
|
-
|
1316
|
-
// Use XDomainRequest for IE if XMLHTTPRequest2 isn't available
|
1317
|
-
// 'withCredentials' is only available in XMLHTTPRequest2
|
1318
|
-
// Also XDomainRequest has a lot of gotchas, so only use if cross domain
|
1319
|
-
if(crossOrigin && window.XDomainRequest && !('withCredentials' in request)) {
|
1320
|
-
request = new window.XDomainRequest();
|
1321
|
-
request.onload = function() {
|
1322
|
-
onSuccess(request.responseText);
|
1323
|
-
};
|
1324
|
-
request.onerror = onError;
|
1325
|
-
// these blank handlers need to be set to fix ie9 http://cypressnorth.com/programming/internet-explorer-aborting-ajax-requests-fixed/
|
1326
|
-
request.onprogress = function() {};
|
1327
|
-
request.ontimeout = onError;
|
1328
|
-
|
1329
|
-
// XMLHTTPRequest
|
1330
|
-
} else {
|
1331
|
-
fileUrl = (urlInfo.protocol == 'file:' || winLoc.protocol == 'file:');
|
1332
|
-
|
1333
|
-
request.onreadystatechange = function() {
|
1334
|
-
if (request.readyState === 4) {
|
1335
|
-
if (request.status === 200 || fileUrl && request.status === 0) {
|
1336
|
-
onSuccess(request.responseText);
|
1337
|
-
} else {
|
1338
|
-
onError(request.responseText);
|
1339
|
-
}
|
1340
|
-
}
|
1341
|
-
};
|
1342
|
-
}
|
1343
|
-
|
1344
|
-
// open the connection
|
1345
|
-
try {
|
1346
|
-
// Third arg is async, or ignored by XDomainRequest
|
1347
|
-
request.open('GET', url, true);
|
1348
|
-
// withCredentials only supported by XMLHttpRequest2
|
1349
|
-
if(withCredentials) {
|
1350
|
-
request.withCredentials = true;
|
1351
|
-
}
|
1352
|
-
} catch(e) {
|
1353
|
-
onError(e);
|
1354
|
-
return;
|
1355
|
-
}
|
1356
|
-
|
1357
|
-
// send the request
|
1358
|
-
try {
|
1359
|
-
request.send();
|
1360
|
-
} catch(e) {
|
1361
|
-
onError(e);
|
1362
|
-
}
|
1363
|
-
};
|
1364
|
-
|
1365
|
-
/**
|
1366
|
-
* Add to local storage (may removeable)
|
1286
|
+
* Add to local storage (may removable)
|
1367
1287
|
* @private
|
1368
1288
|
*/
|
1369
1289
|
vjs.setLocalStorage = function(key, value){
|
@@ -1386,7 +1306,7 @@ vjs.setLocalStorage = function(key, value){
|
|
1386
1306
|
};
|
1387
1307
|
|
1388
1308
|
/**
|
1389
|
-
* Get
|
1309
|
+
* Get absolute version of relative URL. Used to tell flash correct URL.
|
1390
1310
|
* http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
|
1391
1311
|
* @param {String} url URL to make absolute
|
1392
1312
|
* @return {String} Absolute URL
|
@@ -1448,7 +1368,7 @@ vjs.parseUrl = function(url) {
|
|
1448
1368
|
};
|
1449
1369
|
|
1450
1370
|
/**
|
1451
|
-
* Log
|
1371
|
+
* Log messages to the console and history based on the type of message
|
1452
1372
|
*
|
1453
1373
|
* @param {String} type The type of message, or `null` for `log`
|
1454
1374
|
* @param {[type]} args The args to be passed to the log
|
@@ -1578,6 +1498,157 @@ vjs.arr.forEach = function(array, callback, thisArg) {
|
|
1578
1498
|
|
1579
1499
|
return array;
|
1580
1500
|
};
|
1501
|
+
/**
|
1502
|
+
* Simple http request for retrieving external files (e.g. text tracks)
|
1503
|
+
*
|
1504
|
+
* ##### Example
|
1505
|
+
*
|
1506
|
+
* // using url string
|
1507
|
+
* videojs.xhr('http://example.com/myfile.vtt', function(error, response, responseBody){});
|
1508
|
+
*
|
1509
|
+
* // or options block
|
1510
|
+
* videojs.xhr({
|
1511
|
+
* uri: 'http://example.com/myfile.vtt',
|
1512
|
+
* method: 'GET',
|
1513
|
+
* responseType: 'text'
|
1514
|
+
* }, function(error, response, responseBody){
|
1515
|
+
* if (error) {
|
1516
|
+
* // log the error
|
1517
|
+
* } else {
|
1518
|
+
* // successful, do something with the response
|
1519
|
+
* }
|
1520
|
+
* });
|
1521
|
+
*
|
1522
|
+
*
|
1523
|
+
* API is modeled after the Raynos/xhr, which we hope to use after
|
1524
|
+
* getting browserify implemented.
|
1525
|
+
* https://github.com/Raynos/xhr/blob/master/index.js
|
1526
|
+
*
|
1527
|
+
* @param {Object|String} options Options block or URL string
|
1528
|
+
* @param {Function} callback The callback function
|
1529
|
+
* @returns {Object} The request
|
1530
|
+
*/
|
1531
|
+
vjs.xhr = function(options, callback){
|
1532
|
+
var XHR, request, urlInfo, winLoc, fileUrl, crossOrigin, abortTimeout, successHandler, errorHandler;
|
1533
|
+
|
1534
|
+
// If options is a string it's the url
|
1535
|
+
if (typeof options === 'string') {
|
1536
|
+
options = {
|
1537
|
+
uri: options
|
1538
|
+
};
|
1539
|
+
}
|
1540
|
+
|
1541
|
+
// Merge with default options
|
1542
|
+
videojs.util.mergeOptions({
|
1543
|
+
method: 'GET',
|
1544
|
+
timeout: 45 * 1000
|
1545
|
+
}, options);
|
1546
|
+
|
1547
|
+
callback = callback || function(){};
|
1548
|
+
|
1549
|
+
successHandler = function(){
|
1550
|
+
window.clearTimeout(abortTimeout);
|
1551
|
+
callback(null, request, request.response || request.responseText);
|
1552
|
+
};
|
1553
|
+
|
1554
|
+
errorHandler = function(err){
|
1555
|
+
window.clearTimeout(abortTimeout);
|
1556
|
+
|
1557
|
+
if (!err || typeof err === 'string') {
|
1558
|
+
err = new Error(err);
|
1559
|
+
}
|
1560
|
+
|
1561
|
+
callback(err, request);
|
1562
|
+
};
|
1563
|
+
|
1564
|
+
XHR = window.XMLHttpRequest;
|
1565
|
+
|
1566
|
+
if (typeof XHR === 'undefined') {
|
1567
|
+
// Shim XMLHttpRequest for older IEs
|
1568
|
+
XHR = function () {
|
1569
|
+
try { return new window.ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch (e) {}
|
1570
|
+
try { return new window.ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch (f) {}
|
1571
|
+
try { return new window.ActiveXObject('Msxml2.XMLHTTP'); } catch (g) {}
|
1572
|
+
throw new Error('This browser does not support XMLHttpRequest.');
|
1573
|
+
};
|
1574
|
+
}
|
1575
|
+
|
1576
|
+
request = new XHR();
|
1577
|
+
// Store a reference to the url on the request instance
|
1578
|
+
request.uri = options.uri;
|
1579
|
+
|
1580
|
+
urlInfo = vjs.parseUrl(options.uri);
|
1581
|
+
winLoc = window.location;
|
1582
|
+
// Check if url is for another domain/origin
|
1583
|
+
// IE8 doesn't know location.origin, so we won't rely on it here
|
1584
|
+
crossOrigin = (urlInfo.protocol + urlInfo.host) !== (winLoc.protocol + winLoc.host);
|
1585
|
+
|
1586
|
+
// XDomainRequest -- Use for IE if XMLHTTPRequest2 isn't available
|
1587
|
+
// 'withCredentials' is only available in XMLHTTPRequest2
|
1588
|
+
// Also XDomainRequest has a lot of gotchas, so only use if cross domain
|
1589
|
+
if (crossOrigin && window.XDomainRequest && !('withCredentials' in request)) {
|
1590
|
+
request = new window.XDomainRequest();
|
1591
|
+
request.onload = successHandler;
|
1592
|
+
request.onerror = errorHandler;
|
1593
|
+
// These blank handlers need to be set to fix ie9
|
1594
|
+
// http://cypressnorth.com/programming/internet-explorer-aborting-ajax-requests-fixed/
|
1595
|
+
request.onprogress = function(){};
|
1596
|
+
request.ontimeout = function(){};
|
1597
|
+
|
1598
|
+
// XMLHTTPRequest
|
1599
|
+
} else {
|
1600
|
+
fileUrl = (urlInfo.protocol == 'file:' || winLoc.protocol == 'file:');
|
1601
|
+
|
1602
|
+
request.onreadystatechange = function() {
|
1603
|
+
if (request.readyState === 4) {
|
1604
|
+
if (request.timedout) {
|
1605
|
+
return errorHandler('timeout');
|
1606
|
+
}
|
1607
|
+
|
1608
|
+
if (request.status === 200 || fileUrl && request.status === 0) {
|
1609
|
+
successHandler();
|
1610
|
+
} else {
|
1611
|
+
errorHandler();
|
1612
|
+
}
|
1613
|
+
}
|
1614
|
+
};
|
1615
|
+
|
1616
|
+
if (options.timeout) {
|
1617
|
+
abortTimeout = window.setTimeout(function() {
|
1618
|
+
if (request.readyState !== 4) {
|
1619
|
+
request.timedout = true;
|
1620
|
+
request.abort();
|
1621
|
+
}
|
1622
|
+
}, options.timeout);
|
1623
|
+
}
|
1624
|
+
}
|
1625
|
+
|
1626
|
+
// open the connection
|
1627
|
+
try {
|
1628
|
+
// Third arg is async, or ignored by XDomainRequest
|
1629
|
+
request.open(options.method || 'GET', options.uri, true);
|
1630
|
+
} catch(err) {
|
1631
|
+
return errorHandler(err);
|
1632
|
+
}
|
1633
|
+
|
1634
|
+
// withCredentials only supported by XMLHttpRequest2
|
1635
|
+
if(options.withCredentials) {
|
1636
|
+
request.withCredentials = true;
|
1637
|
+
}
|
1638
|
+
|
1639
|
+
if (options.responseType) {
|
1640
|
+
request.responseType = options.responseType;
|
1641
|
+
}
|
1642
|
+
|
1643
|
+
// send the request
|
1644
|
+
try {
|
1645
|
+
request.send();
|
1646
|
+
} catch(err) {
|
1647
|
+
return errorHandler(err);
|
1648
|
+
}
|
1649
|
+
|
1650
|
+
return request;
|
1651
|
+
};
|
1581
1652
|
/**
|
1582
1653
|
* Utility functions namespace
|
1583
1654
|
* @namespace
|
@@ -2177,7 +2248,7 @@ vjs.Component.prototype.buildCSSClass = function(){
|
|
2177
2248
|
*
|
2178
2249
|
* The benefit of using this over `vjs.on(otherElement, 'eventName', myFunc)`
|
2179
2250
|
* and `otherComponent.on('eventName', myFunc)` is that this way the listeners
|
2180
|
-
* will be automatically cleaned up when either component is
|
2251
|
+
* will be automatically cleaned up when either component is disposed.
|
2181
2252
|
* It will also bind myComponent as the context of myFunc.
|
2182
2253
|
*
|
2183
2254
|
* **NOTE**: When using this on elements in the page other than window
|
@@ -2358,7 +2429,7 @@ vjs.Component.prototype.isReady_;
|
|
2358
2429
|
*
|
2359
2430
|
* Allows for delaying ready. Override on a sub class prototype.
|
2360
2431
|
* If you set this.isReadyOnInitFinish_ it will affect all components.
|
2361
|
-
* Specially used when waiting for the Flash player to
|
2432
|
+
* Specially used when waiting for the Flash player to asynchronously load.
|
2362
2433
|
*
|
2363
2434
|
* @type {Boolean}
|
2364
2435
|
* @private
|
@@ -2376,7 +2447,7 @@ vjs.Component.prototype.readyQueue_;
|
|
2376
2447
|
/**
|
2377
2448
|
* Bind a listener to the component's ready state
|
2378
2449
|
*
|
2379
|
-
* Different from event listeners in that if the ready event has already
|
2450
|
+
* Different from event listeners in that if the ready event has already happened
|
2380
2451
|
* it will trigger the function immediately.
|
2381
2452
|
*
|
2382
2453
|
* @param {Function} fn Ready listener
|
@@ -2502,7 +2573,7 @@ vjs.Component.prototype.unlockShowing = function(){
|
|
2502
2573
|
/**
|
2503
2574
|
* Disable component by making it unshowable
|
2504
2575
|
*
|
2505
|
-
* Currently private because we're
|
2576
|
+
* Currently private because we're moving towards more css-based states.
|
2506
2577
|
* @private
|
2507
2578
|
*/
|
2508
2579
|
vjs.Component.prototype.disable = function(){
|
@@ -2640,7 +2711,7 @@ vjs.Component.prototype.onResize;
|
|
2640
2711
|
*
|
2641
2712
|
* This is used to support toggling the controls through a tap on the video.
|
2642
2713
|
*
|
2643
|
-
* We're
|
2714
|
+
* We're requiring them to be enabled because otherwise every component would
|
2644
2715
|
* have this extra overhead unnecessarily, on mobile devices where extra
|
2645
2716
|
* overhead is especially bad.
|
2646
2717
|
* @private
|
@@ -2749,15 +2820,15 @@ vjs.Component.prototype.enableTouchActivity = function() {
|
|
2749
2820
|
// For as long as the they are touching the device or have their mouse down,
|
2750
2821
|
// we consider them active even if they're not moving their finger or mouse.
|
2751
2822
|
// So we want to continue to update that they are active
|
2752
|
-
clearInterval(touchHolding);
|
2823
|
+
this.clearInterval(touchHolding);
|
2753
2824
|
// report at the same interval as activityCheck
|
2754
|
-
touchHolding = setInterval(report, 250);
|
2825
|
+
touchHolding = this.setInterval(report, 250);
|
2755
2826
|
});
|
2756
2827
|
|
2757
2828
|
touchEnd = function(event) {
|
2758
2829
|
report();
|
2759
2830
|
// stop the interval that maintains activity if the touch is holding
|
2760
|
-
clearInterval(touchHolding);
|
2831
|
+
this.clearInterval(touchHolding);
|
2761
2832
|
};
|
2762
2833
|
|
2763
2834
|
this.on('touchmove', report);
|
@@ -2765,6 +2836,83 @@ vjs.Component.prototype.enableTouchActivity = function() {
|
|
2765
2836
|
this.on('touchcancel', touchEnd);
|
2766
2837
|
};
|
2767
2838
|
|
2839
|
+
/**
|
2840
|
+
* Creates timeout and sets up disposal automatically.
|
2841
|
+
* @param {Function} fn The function to run after the timeout.
|
2842
|
+
* @param {Number} timeout Number of ms to delay before executing specified function.
|
2843
|
+
* @return {Number} Returns the timeout ID
|
2844
|
+
*/
|
2845
|
+
vjs.Component.prototype.setTimeout = function(fn, timeout) {
|
2846
|
+
fn = vjs.bind(this, fn);
|
2847
|
+
|
2848
|
+
// window.setTimeout would be preferable here, but due to some bizarre issue with Sinon and/or Phantomjs, we can't.
|
2849
|
+
var timeoutId = setTimeout(fn, timeout);
|
2850
|
+
|
2851
|
+
var disposeFn = function() {
|
2852
|
+
this.clearTimeout(timeoutId);
|
2853
|
+
};
|
2854
|
+
|
2855
|
+
disposeFn.guid = 'vjs-timeout-'+ timeoutId;
|
2856
|
+
|
2857
|
+
this.on('dispose', disposeFn);
|
2858
|
+
|
2859
|
+
return timeoutId;
|
2860
|
+
};
|
2861
|
+
|
2862
|
+
|
2863
|
+
/**
|
2864
|
+
* Clears a timeout and removes the associated dispose listener
|
2865
|
+
* @param {Number} timeoutId The id of the timeout to clear
|
2866
|
+
* @return {Number} Returns the timeout ID
|
2867
|
+
*/
|
2868
|
+
vjs.Component.prototype.clearTimeout = function(timeoutId) {
|
2869
|
+
clearTimeout(timeoutId);
|
2870
|
+
|
2871
|
+
var disposeFn = function(){};
|
2872
|
+
disposeFn.guid = 'vjs-timeout-'+ timeoutId;
|
2873
|
+
|
2874
|
+
this.off('dispose', disposeFn);
|
2875
|
+
|
2876
|
+
return timeoutId;
|
2877
|
+
};
|
2878
|
+
|
2879
|
+
/**
|
2880
|
+
* Creates an interval and sets up disposal automatically.
|
2881
|
+
* @param {Function} fn The function to run every N seconds.
|
2882
|
+
* @param {Number} interval Number of ms to delay before executing specified function.
|
2883
|
+
* @return {Number} Returns the interval ID
|
2884
|
+
*/
|
2885
|
+
vjs.Component.prototype.setInterval = function(fn, interval) {
|
2886
|
+
fn = vjs.bind(this, fn);
|
2887
|
+
|
2888
|
+
var intervalId = setInterval(fn, interval);
|
2889
|
+
|
2890
|
+
var disposeFn = function() {
|
2891
|
+
this.clearInterval(intervalId);
|
2892
|
+
};
|
2893
|
+
|
2894
|
+
disposeFn.guid = 'vjs-interval-'+ intervalId;
|
2895
|
+
|
2896
|
+
this.on('dispose', disposeFn);
|
2897
|
+
|
2898
|
+
return intervalId;
|
2899
|
+
};
|
2900
|
+
|
2901
|
+
/**
|
2902
|
+
* Clears an interval and removes the associated dispose listener
|
2903
|
+
* @param {Number} intervalId The id of the interval to clear
|
2904
|
+
* @return {Number} Returns the interval ID
|
2905
|
+
*/
|
2906
|
+
vjs.Component.prototype.clearInterval = function(intervalId) {
|
2907
|
+
clearInterval(intervalId);
|
2908
|
+
|
2909
|
+
var disposeFn = function(){};
|
2910
|
+
disposeFn.guid = 'vjs-interval-'+ intervalId;
|
2911
|
+
|
2912
|
+
this.off('dispose', disposeFn);
|
2913
|
+
|
2914
|
+
return intervalId;
|
2915
|
+
};
|
2768
2916
|
/* Button - Base class for all buttons
|
2769
2917
|
================================================================================ */
|
2770
2918
|
/**
|
@@ -2874,24 +3022,9 @@ vjs.Slider = vjs.Component.extend({
|
|
2874
3022
|
|
2875
3023
|
this.on(player, 'controlsvisible', this.update);
|
2876
3024
|
this.on(player, this.playerEvent, this.update);
|
2877
|
-
|
2878
|
-
this.boundEvents = {};
|
2879
|
-
this.boundEvents.move = vjs.bind(this, this.onMouseMove);
|
2880
|
-
this.boundEvents.end = vjs.bind(this, this.onMouseUp);
|
2881
3025
|
}
|
2882
3026
|
});
|
2883
3027
|
|
2884
|
-
vjs.Slider.prototype.dispose = function() {
|
2885
|
-
vjs.off(document, 'mousemove', this.boundEvents.move, false);
|
2886
|
-
vjs.off(document, 'mouseup', this.boundEvents.end, false);
|
2887
|
-
vjs.off(document, 'touchmove', this.boundEvents.move, false);
|
2888
|
-
vjs.off(document, 'touchend', this.boundEvents.end, false);
|
2889
|
-
|
2890
|
-
vjs.off(document, 'keyup', vjs.bind(this, this.onKeyPress));
|
2891
|
-
|
2892
|
-
vjs.Component.prototype.dispose.call(this);
|
2893
|
-
};
|
2894
|
-
|
2895
3028
|
vjs.Slider.prototype.createEl = function(type, props) {
|
2896
3029
|
props = props || {};
|
2897
3030
|
// Add the slider element class to all sub classes
|
@@ -2912,10 +3045,10 @@ vjs.Slider.prototype.onMouseDown = function(event){
|
|
2912
3045
|
vjs.blockTextSelection();
|
2913
3046
|
this.addClass('vjs-sliding');
|
2914
3047
|
|
2915
|
-
|
2916
|
-
|
2917
|
-
|
2918
|
-
|
3048
|
+
this.on(document, 'mousemove', this.onMouseMove);
|
3049
|
+
this.on(document, 'mouseup', this.onMouseUp);
|
3050
|
+
this.on(document, 'touchmove', this.onMouseMove);
|
3051
|
+
this.on(document, 'touchend', this.onMouseUp);
|
2919
3052
|
|
2920
3053
|
this.onMouseMove(event);
|
2921
3054
|
};
|
@@ -2927,10 +3060,10 @@ vjs.Slider.prototype.onMouseUp = function() {
|
|
2927
3060
|
vjs.unblockTextSelection();
|
2928
3061
|
this.removeClass('vjs-sliding');
|
2929
3062
|
|
2930
|
-
|
2931
|
-
|
2932
|
-
|
2933
|
-
|
3063
|
+
this.off(document, 'mousemove', this.onMouseMove);
|
3064
|
+
this.off(document, 'mouseup', this.onMouseUp);
|
3065
|
+
this.off(document, 'touchmove', this.onMouseMove);
|
3066
|
+
this.off(document, 'touchend', this.onMouseUp);
|
2934
3067
|
|
2935
3068
|
this.update();
|
2936
3069
|
};
|
@@ -3037,7 +3170,7 @@ vjs.Slider.prototype.calculateDistance = function(event){
|
|
3037
3170
|
};
|
3038
3171
|
|
3039
3172
|
vjs.Slider.prototype.onFocus = function(){
|
3040
|
-
|
3173
|
+
this.on(document, 'keydown', this.onKeyPress);
|
3041
3174
|
};
|
3042
3175
|
|
3043
3176
|
vjs.Slider.prototype.onKeyPress = function(event){
|
@@ -3051,7 +3184,7 @@ vjs.Slider.prototype.onKeyPress = function(event){
|
|
3051
3184
|
};
|
3052
3185
|
|
3053
3186
|
vjs.Slider.prototype.onBlur = function(){
|
3054
|
-
|
3187
|
+
this.off(document, 'keydown', this.onKeyPress);
|
3055
3188
|
};
|
3056
3189
|
|
3057
3190
|
/**
|
@@ -3205,7 +3338,7 @@ vjs.MenuButton = vjs.Button.extend({
|
|
3205
3338
|
this.hide();
|
3206
3339
|
}
|
3207
3340
|
|
3208
|
-
this.on('
|
3341
|
+
this.on('keydown', this.onKeyPress);
|
3209
3342
|
this.el_.setAttribute('aria-haspopup', true);
|
3210
3343
|
this.el_.setAttribute('role', 'button');
|
3211
3344
|
}
|
@@ -3380,7 +3513,7 @@ for (var errNum = 0; errNum < vjs.MediaError.errorTypes.length; errNum++) {
|
|
3380
3513
|
var apiMap, specApi, browserApi, i;
|
3381
3514
|
|
3382
3515
|
/**
|
3383
|
-
* Store the browser-
|
3516
|
+
* Store the browser-specific methods for the fullscreen API
|
3384
3517
|
* @type {Object|undefined}
|
3385
3518
|
* @private
|
3386
3519
|
*/
|
@@ -3568,7 +3701,7 @@ vjs.Player = vjs.Component.extend({
|
|
3568
3701
|
});
|
3569
3702
|
|
3570
3703
|
/**
|
3571
|
-
* The
|
3704
|
+
* The player's stored language code
|
3572
3705
|
*
|
3573
3706
|
* @type {String}
|
3574
3707
|
* @private
|
@@ -3591,7 +3724,7 @@ vjs.Player.prototype.language = function (languageCode) {
|
|
3591
3724
|
};
|
3592
3725
|
|
3593
3726
|
/**
|
3594
|
-
* The
|
3727
|
+
* The player's stored language dictionary
|
3595
3728
|
*
|
3596
3729
|
* @type {Object}
|
3597
3730
|
* @private
|
@@ -3775,7 +3908,7 @@ vjs.Player.prototype.createEl = function(){
|
|
3775
3908
|
|
3776
3909
|
// /* Media Technology (tech)
|
3777
3910
|
// ================================================================================ */
|
3778
|
-
// Load/Create an instance of playback
|
3911
|
+
// Load/Create an instance of playback technology including element and API methods
|
3779
3912
|
// And append playback element in player div.
|
3780
3913
|
vjs.Player.prototype.loadTech = function(techName, source){
|
3781
3914
|
|
@@ -3914,7 +4047,7 @@ vjs.Player.prototype.onPlay = function(){
|
|
3914
4047
|
};
|
3915
4048
|
|
3916
4049
|
/**
|
3917
|
-
* Fired whenever the media begins
|
4050
|
+
* Fired whenever the media begins waiting
|
3918
4051
|
* @event waiting
|
3919
4052
|
*/
|
3920
4053
|
vjs.Player.prototype.onWaiting = function(){
|
@@ -3922,7 +4055,7 @@ vjs.Player.prototype.onWaiting = function(){
|
|
3922
4055
|
};
|
3923
4056
|
|
3924
4057
|
/**
|
3925
|
-
* A handler for events that signal that waiting has
|
4058
|
+
* A handler for events that signal that waiting has ended
|
3926
4059
|
* which is not consistent between browsers. See #1351
|
3927
4060
|
* @private
|
3928
4061
|
*/
|
@@ -4012,7 +4145,7 @@ vjs.Player.prototype.onEnded = function(){
|
|
4012
4145
|
* @event durationchange
|
4013
4146
|
*/
|
4014
4147
|
vjs.Player.prototype.onDurationChange = function(){
|
4015
|
-
// Allows for
|
4148
|
+
// Allows for caching value instead of asking player each time.
|
4016
4149
|
// We need to get the techGet response and check for a value so we don't
|
4017
4150
|
// accidentally cause the stack to blow up.
|
4018
4151
|
var duration = this.techGet('duration');
|
@@ -4170,7 +4303,7 @@ vjs.Player.prototype.currentTime = function(seconds){
|
|
4170
4303
|
// cache last currentTime and return. default to 0 seconds
|
4171
4304
|
//
|
4172
4305
|
// Caching the currentTime is meant to prevent a massive amount of reads on the tech's
|
4173
|
-
// currentTime when scrubbing, but may not provide much
|
4306
|
+
// currentTime when scrubbing, but may not provide much performance benefit afterall.
|
4174
4307
|
// Should be tested. Also something has to read the actual current time or the cache will
|
4175
4308
|
// never get updated.
|
4176
4309
|
return this.cache_.currentTime = (this.techGet('currentTime') || 0);
|
@@ -4190,7 +4323,7 @@ vjs.Player.prototype.currentTime = function(seconds){
|
|
4190
4323
|
vjs.Player.prototype.duration = function(seconds){
|
4191
4324
|
if (seconds !== undefined) {
|
4192
4325
|
|
4193
|
-
// cache the last set value for
|
4326
|
+
// cache the last set value for optimized scrubbing (esp. Flash)
|
4194
4327
|
this.cache_.duration = parseFloat(seconds);
|
4195
4328
|
|
4196
4329
|
return this;
|
@@ -4356,7 +4489,7 @@ vjs.Player.prototype.muted = function(muted){
|
|
4356
4489
|
};
|
4357
4490
|
|
4358
4491
|
// Check if current tech can support native fullscreen
|
4359
|
-
// (e.g. with built in controls
|
4492
|
+
// (e.g. with built in controls like iOS, so not our flash swf)
|
4360
4493
|
vjs.Player.prototype.supportsFullScreen = function(){
|
4361
4494
|
return this.techGet('supportsFullScreen') || false;
|
4362
4495
|
};
|
@@ -4427,7 +4560,7 @@ vjs.Player.prototype.requestFullscreen = function(){
|
|
4427
4560
|
|
4428
4561
|
// Trigger fullscreenchange event after change
|
4429
4562
|
// We have to specifically add this each time, and remove
|
4430
|
-
// when
|
4563
|
+
// when canceling fullscreen. Otherwise if there's multiple
|
4431
4564
|
// players on a page, they would all be reacting to the same fullscreen
|
4432
4565
|
// events
|
4433
4566
|
vjs.on(document, fsApi['fullscreenchange'], vjs.bind(this, function(e){
|
@@ -4544,7 +4677,6 @@ vjs.Player.prototype.exitFullWindow = function(){
|
|
4544
4677
|
};
|
4545
4678
|
|
4546
4679
|
vjs.Player.prototype.selectSource = function(sources){
|
4547
|
-
|
4548
4680
|
// Loop through each playback technology in the options order
|
4549
4681
|
for (var i=0,j=this.options_['techOrder'];i<j.length;i++) {
|
4550
4682
|
var techName = vjs.capitalize(j[i]),
|
@@ -4633,7 +4765,14 @@ vjs.Player.prototype.src = function(source){
|
|
4633
4765
|
|
4634
4766
|
// wait until the tech is ready to set the source
|
4635
4767
|
this.ready(function(){
|
4636
|
-
|
4768
|
+
|
4769
|
+
// The setSource tech method was added with source handlers
|
4770
|
+
// so older techs won't support it
|
4771
|
+
if (this.tech['setSource']) {
|
4772
|
+
this.techCall('setSource', source);
|
4773
|
+
} else {
|
4774
|
+
this.techCall('src', source.src);
|
4775
|
+
}
|
4637
4776
|
|
4638
4777
|
if (this.options_['preload'] == 'auto') {
|
4639
4778
|
this.load();
|
@@ -4655,8 +4794,7 @@ vjs.Player.prototype.src = function(source){
|
|
4655
4794
|
* @private
|
4656
4795
|
*/
|
4657
4796
|
vjs.Player.prototype.sourceList_ = function(sources){
|
4658
|
-
var sourceTech = this.selectSource(sources)
|
4659
|
-
errorTimeout;
|
4797
|
+
var sourceTech = this.selectSource(sources);
|
4660
4798
|
|
4661
4799
|
if (sourceTech) {
|
4662
4800
|
if (sourceTech.tech === this.techName) {
|
@@ -4668,17 +4806,13 @@ vjs.Player.prototype.sourceList_ = function(sources){
|
|
4668
4806
|
}
|
4669
4807
|
} else {
|
4670
4808
|
// We need to wrap this in a timeout to give folks a chance to add error event handlers
|
4671
|
-
|
4809
|
+
this.setTimeout( function() {
|
4672
4810
|
this.error({ code: 4, message: this.localize(this.options()['notSupportedMessage']) });
|
4673
|
-
}
|
4811
|
+
}, 0);
|
4674
4812
|
|
4675
4813
|
// we could not find an appropriate tech, but let's still notify the delegate that this is it
|
4676
4814
|
// this needs a better comment about why this is needed
|
4677
4815
|
this.triggerReady();
|
4678
|
-
|
4679
|
-
this.on('dispose', function() {
|
4680
|
-
clearTimeout(errorTimeout);
|
4681
|
-
});
|
4682
4816
|
}
|
4683
4817
|
};
|
4684
4818
|
|
@@ -5009,17 +5143,17 @@ vjs.Player.prototype.listenForUserActivity = function(){
|
|
5009
5143
|
// For as long as the they are touching the device or have their mouse down,
|
5010
5144
|
// we consider them active even if they're not moving their finger or mouse.
|
5011
5145
|
// So we want to continue to update that they are active
|
5012
|
-
clearInterval(mouseInProgress);
|
5146
|
+
this.clearInterval(mouseInProgress);
|
5013
5147
|
// Setting userActivity=true now and setting the interval to the same time
|
5014
5148
|
// as the activityCheck interval (250) should ensure we never miss the
|
5015
5149
|
// next activityCheck
|
5016
|
-
mouseInProgress = setInterval(onActivity, 250);
|
5150
|
+
mouseInProgress = this.setInterval(onActivity, 250);
|
5017
5151
|
};
|
5018
5152
|
|
5019
5153
|
onMouseUp = function(event) {
|
5020
5154
|
onActivity();
|
5021
5155
|
// Stop the interval that maintains activity if the mouse/touch is down
|
5022
|
-
clearInterval(mouseInProgress);
|
5156
|
+
this.clearInterval(mouseInProgress);
|
5023
5157
|
};
|
5024
5158
|
|
5025
5159
|
// Any mouse movement will be considered user activity
|
@@ -5037,7 +5171,7 @@ vjs.Player.prototype.listenForUserActivity = function(){
|
|
5037
5171
|
// `this.reportUserActivity` simply sets this.userActivity_ to true, which
|
5038
5172
|
// then gets picked up by this loop
|
5039
5173
|
// http://ejohn.org/blog/learning-from-twitter/
|
5040
|
-
activityCheck = setInterval(
|
5174
|
+
activityCheck = this.setInterval(function() {
|
5041
5175
|
// Check to see if mouse/touch activity has happened
|
5042
5176
|
if (this.userActivity_) {
|
5043
5177
|
// Reset the activity tracker
|
@@ -5047,29 +5181,23 @@ vjs.Player.prototype.listenForUserActivity = function(){
|
|
5047
5181
|
this.userActive(true);
|
5048
5182
|
|
5049
5183
|
// Clear any existing inactivity timeout to start the timer over
|
5050
|
-
clearTimeout(inactivityTimeout);
|
5184
|
+
this.clearTimeout(inactivityTimeout);
|
5051
5185
|
|
5052
5186
|
var timeout = this.options()['inactivityTimeout'];
|
5053
5187
|
if (timeout > 0) {
|
5054
5188
|
// In <timeout> milliseconds, if no more activity has occurred the
|
5055
5189
|
// user will be considered inactive
|
5056
|
-
inactivityTimeout = setTimeout(
|
5190
|
+
inactivityTimeout = this.setTimeout(function () {
|
5057
5191
|
// Protect against the case where the inactivityTimeout can trigger just
|
5058
5192
|
// before the next user activity is picked up by the activityCheck loop
|
5059
5193
|
// causing a flicker
|
5060
5194
|
if (!this.userActivity_) {
|
5061
5195
|
this.userActive(false);
|
5062
5196
|
}
|
5063
|
-
}
|
5197
|
+
}, timeout);
|
5064
5198
|
}
|
5065
5199
|
}
|
5066
|
-
}
|
5067
|
-
|
5068
|
-
// Clean up the intervals when we kill the player
|
5069
|
-
this.on('dispose', function(){
|
5070
|
-
clearInterval(activityCheck);
|
5071
|
-
clearTimeout(inactivityTimeout);
|
5072
|
-
});
|
5200
|
+
}, 250);
|
5073
5201
|
};
|
5074
5202
|
|
5075
5203
|
/**
|
@@ -5567,13 +5695,13 @@ vjs.LoadProgressBar.prototype.update = function(){
|
|
5567
5695
|
part = children[i];
|
5568
5696
|
|
5569
5697
|
if (!part) {
|
5570
|
-
part = this.el_.appendChild(vjs.createEl())
|
5571
|
-
}
|
5698
|
+
part = this.el_.appendChild(vjs.createEl());
|
5699
|
+
}
|
5572
5700
|
|
5573
5701
|
// set the percent based on the width of the progress bar (bufferedEnd)
|
5574
5702
|
part.style.left = percentify(start, bufferedEnd);
|
5575
5703
|
part.style.width = percentify(end - start, bufferedEnd);
|
5576
|
-
}
|
5704
|
+
}
|
5577
5705
|
|
5578
5706
|
// remove unused buffered range elements
|
5579
5707
|
for (i = children.length; i > buffered.length; i--) {
|
@@ -5948,7 +6076,7 @@ vjs.PlaybackRateMenuButton.prototype.createMenu = function(){
|
|
5948
6076
|
menu.addChild(
|
5949
6077
|
new vjs.PlaybackRateMenuItem(this.player(), { 'rate': rates[i] + 'x'})
|
5950
6078
|
);
|
5951
|
-
}
|
6079
|
+
}
|
5952
6080
|
}
|
5953
6081
|
|
5954
6082
|
return menu;
|
@@ -5970,7 +6098,7 @@ vjs.PlaybackRateMenuButton.prototype.onClick = function(){
|
|
5970
6098
|
newRate = rates[i];
|
5971
6099
|
break;
|
5972
6100
|
}
|
5973
|
-
}
|
6101
|
+
}
|
5974
6102
|
this.player().playbackRate(newRate);
|
5975
6103
|
};
|
5976
6104
|
|
@@ -6250,7 +6378,7 @@ vjs.MediaTechController = vjs.Component.extend({
|
|
6250
6378
|
this.manualProgressOn();
|
6251
6379
|
}
|
6252
6380
|
|
6253
|
-
// Manually track
|
6381
|
+
// Manually track timeupdates in cases where the browser/flash player doesn't report it.
|
6254
6382
|
if (!this['featuresTimeupdateEvents']) {
|
6255
6383
|
this.manualTimeUpdatesOn();
|
6256
6384
|
}
|
@@ -6404,8 +6532,7 @@ vjs.MediaTechController.prototype.manualProgressOff = function(){
|
|
6404
6532
|
};
|
6405
6533
|
|
6406
6534
|
vjs.MediaTechController.prototype.trackProgress = function(){
|
6407
|
-
|
6408
|
-
this.progressInterval = setInterval(vjs.bind(this, function(){
|
6535
|
+
this.progressInterval = this.setInterval(function(){
|
6409
6536
|
// Don't trigger unless buffered amount is greater than last time
|
6410
6537
|
|
6411
6538
|
var bufferedPercent = this.player().bufferedPercent();
|
@@ -6419,9 +6546,9 @@ vjs.MediaTechController.prototype.trackProgress = function(){
|
|
6419
6546
|
if (bufferedPercent === 1) {
|
6420
6547
|
this.stopTrackingProgress();
|
6421
6548
|
}
|
6422
|
-
}
|
6549
|
+
}, 500);
|
6423
6550
|
};
|
6424
|
-
vjs.MediaTechController.prototype.stopTrackingProgress = function(){ clearInterval(this.progressInterval); };
|
6551
|
+
vjs.MediaTechController.prototype.stopTrackingProgress = function(){ this.clearInterval(this.progressInterval); };
|
6425
6552
|
|
6426
6553
|
/*! Time Tracking -------------------------------------------------------------- */
|
6427
6554
|
vjs.MediaTechController.prototype.manualTimeUpdatesOn = function(){
|
@@ -6451,14 +6578,14 @@ vjs.MediaTechController.prototype.manualTimeUpdatesOff = function(){
|
|
6451
6578
|
|
6452
6579
|
vjs.MediaTechController.prototype.trackCurrentTime = function(){
|
6453
6580
|
if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); }
|
6454
|
-
this.currentTimeInterval = setInterval(
|
6581
|
+
this.currentTimeInterval = this.setInterval(function(){
|
6455
6582
|
this.player().trigger('timeupdate');
|
6456
|
-
}
|
6583
|
+
}, 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
|
6457
6584
|
};
|
6458
6585
|
|
6459
6586
|
// Turn off play progress tracking (when paused or dragging)
|
6460
6587
|
vjs.MediaTechController.prototype.stopTrackingCurrentTime = function(){
|
6461
|
-
clearInterval(this.currentTimeInterval);
|
6588
|
+
this.clearInterval(this.currentTimeInterval);
|
6462
6589
|
|
6463
6590
|
// #1002 - if the video ends right before the next timeupdate would happen,
|
6464
6591
|
// the progress bar won't make it all the way to the end
|
@@ -6498,7 +6625,106 @@ vjs.MediaTechController.prototype['featuresPlaybackRate'] = false;
|
|
6498
6625
|
vjs.MediaTechController.prototype['featuresProgressEvents'] = false;
|
6499
6626
|
vjs.MediaTechController.prototype['featuresTimeupdateEvents'] = false;
|
6500
6627
|
|
6501
|
-
|
6628
|
+
/**
|
6629
|
+
* A functional mixin for techs that want to use the Source Handler pattern.
|
6630
|
+
*
|
6631
|
+
* ##### EXAMPLE:
|
6632
|
+
*
|
6633
|
+
* videojs.MediaTechController.withSourceHandlers.call(MyTech);
|
6634
|
+
*
|
6635
|
+
*/
|
6636
|
+
vjs.MediaTechController.withSourceHandlers = function(Tech){
|
6637
|
+
/**
|
6638
|
+
* Register a source handler
|
6639
|
+
* Source handlers are scripts for handling specific formats.
|
6640
|
+
* The source handler pattern is used for adaptive formats (HLS, DASH) that
|
6641
|
+
* manually load video data and feed it into a Source Buffer (Media Source Extensions)
|
6642
|
+
* @param {Function} handler The source handler
|
6643
|
+
* @param {Boolean} first Register it before any existing handlers
|
6644
|
+
*/
|
6645
|
+
Tech.registerSourceHandler = function(handler, index){
|
6646
|
+
var handlers = Tech.sourceHandlers;
|
6647
|
+
|
6648
|
+
if (!handlers) {
|
6649
|
+
handlers = Tech.sourceHandlers = [];
|
6650
|
+
}
|
6651
|
+
|
6652
|
+
if (index === undefined) {
|
6653
|
+
// add to the end of the list
|
6654
|
+
index = handlers.length;
|
6655
|
+
}
|
6656
|
+
|
6657
|
+
handlers.splice(index, 0, handler);
|
6658
|
+
};
|
6659
|
+
|
6660
|
+
/**
|
6661
|
+
* Return the first source handler that supports the source
|
6662
|
+
* TODO: Answer question: should 'probably' be prioritized over 'maybe'
|
6663
|
+
* @param {Object} source The source object
|
6664
|
+
* @returns {Object} The first source handler that supports the source
|
6665
|
+
* @returns {null} Null if no source handler is found
|
6666
|
+
*/
|
6667
|
+
Tech.selectSourceHandler = function(source){
|
6668
|
+
var handlers = Tech.sourceHandlers || [],
|
6669
|
+
can;
|
6670
|
+
|
6671
|
+
for (var i = 0; i < handlers.length; i++) {
|
6672
|
+
can = handlers[i].canHandleSource(source);
|
6673
|
+
|
6674
|
+
if (can) {
|
6675
|
+
return handlers[i];
|
6676
|
+
}
|
6677
|
+
}
|
6678
|
+
|
6679
|
+
return null;
|
6680
|
+
};
|
6681
|
+
|
6682
|
+
/**
|
6683
|
+
* Check if the tech can support the given source
|
6684
|
+
* @param {Object} srcObj The source object
|
6685
|
+
* @return {String} 'probably', 'maybe', or '' (empty string)
|
6686
|
+
*/
|
6687
|
+
Tech.canPlaySource = function(srcObj){
|
6688
|
+
var sh = Tech.selectSourceHandler(srcObj);
|
6689
|
+
|
6690
|
+
if (sh) {
|
6691
|
+
return sh.canHandleSource(srcObj);
|
6692
|
+
}
|
6693
|
+
|
6694
|
+
return '';
|
6695
|
+
};
|
6696
|
+
|
6697
|
+
/**
|
6698
|
+
* Create a function for setting the source using a source object
|
6699
|
+
* and source handlers.
|
6700
|
+
* Should never be called unless a source handler was found.
|
6701
|
+
* @param {Object} source A source object with src and type keys
|
6702
|
+
* @return {vjs.MediaTechController} self
|
6703
|
+
*/
|
6704
|
+
Tech.prototype.setSource = function(source){
|
6705
|
+
var sh = Tech.selectSourceHandler(source);
|
6706
|
+
|
6707
|
+
// Dispose any existing source handler
|
6708
|
+
this.disposeSourceHandler();
|
6709
|
+
this.off('dispose', this.disposeSourceHandler);
|
6710
|
+
|
6711
|
+
this.currentSource_ = source;
|
6712
|
+
this.sourceHandler_ = sh.handleSource(source, this);
|
6713
|
+
this.on('dispose', this.disposeSourceHandler);
|
6714
|
+
|
6715
|
+
return this;
|
6716
|
+
};
|
6717
|
+
|
6718
|
+
/**
|
6719
|
+
* Clean up any existing source handler
|
6720
|
+
*/
|
6721
|
+
Tech.prototype.disposeSourceHandler = function(){
|
6722
|
+
if (this.sourceHandler_ && this.sourceHandler_.dispose) {
|
6723
|
+
this.sourceHandler_.dispose();
|
6724
|
+
}
|
6725
|
+
};
|
6726
|
+
|
6727
|
+
};
|
6502
6728
|
/**
|
6503
6729
|
* @fileoverview HTML5 Media Controller - Wrapper for HTML5 Media API
|
6504
6730
|
*/
|
@@ -6513,22 +6739,8 @@ vjs.media = {};
|
|
6513
6739
|
vjs.Html5 = vjs.MediaTechController.extend({
|
6514
6740
|
/** @constructor */
|
6515
6741
|
init: function(player, options, ready){
|
6516
|
-
// volume cannot be changed from 1 on iOS
|
6517
|
-
this['featuresVolumeControl'] = vjs.Html5.canControlVolume();
|
6518
|
-
|
6519
|
-
// just in case; or is it excessively...
|
6520
|
-
this['featuresPlaybackRate'] = vjs.Html5.canControlPlaybackRate();
|
6521
|
-
|
6522
|
-
// In iOS, if you move a video element in the DOM, it breaks video playback.
|
6523
|
-
this['movingMediaElementInDOM'] = !vjs.IS_IOS;
|
6524
|
-
|
6525
|
-
// HTML video is able to automatically resize when going to fullscreen
|
6526
|
-
this['featuresFullscreenResize'] = true;
|
6527
|
-
|
6528
|
-
// HTML video supports progress events
|
6529
|
-
this['featuresProgressEvents'] = true;
|
6530
|
-
|
6531
6742
|
vjs.MediaTechController.call(this, player, options, ready);
|
6743
|
+
|
6532
6744
|
this.setupTriggers();
|
6533
6745
|
|
6534
6746
|
var source = options['source'];
|
@@ -6537,8 +6749,8 @@ vjs.Html5 = vjs.MediaTechController.extend({
|
|
6537
6749
|
// 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted)
|
6538
6750
|
// 2) Check to see if the network state of the tag was failed at init, and if so, reset the source
|
6539
6751
|
// anyway so the error gets fired.
|
6540
|
-
if (source && (this.el_.currentSrc !== source.src
|
6541
|
-
this.
|
6752
|
+
if (source && (this.el_.currentSrc !== source.src || (player.tag && player.tag.initNetworkState_ === 3))) {
|
6753
|
+
this.setSource(source);
|
6542
6754
|
}
|
6543
6755
|
|
6544
6756
|
// Determine if native controls should be used
|
@@ -6734,7 +6946,7 @@ vjs.Html5.prototype.enterFullScreen = function(){
|
|
6734
6946
|
|
6735
6947
|
// playing and pausing synchronously during the transition to fullscreen
|
6736
6948
|
// can get iOS ~6.1 devices into a play/pause loop
|
6737
|
-
setTimeout(function(){
|
6949
|
+
this.setTimeout(function(){
|
6738
6950
|
video.pause();
|
6739
6951
|
video.webkitEnterFullScreen();
|
6740
6952
|
}, 0);
|
@@ -6742,16 +6954,25 @@ vjs.Html5.prototype.enterFullScreen = function(){
|
|
6742
6954
|
video.webkitEnterFullScreen();
|
6743
6955
|
}
|
6744
6956
|
};
|
6957
|
+
|
6745
6958
|
vjs.Html5.prototype.exitFullScreen = function(){
|
6746
6959
|
this.el_.webkitExitFullScreen();
|
6747
6960
|
};
|
6961
|
+
|
6962
|
+
|
6748
6963
|
vjs.Html5.prototype.src = function(src) {
|
6749
6964
|
if (src === undefined) {
|
6750
6965
|
return this.el_.src;
|
6751
6966
|
} else {
|
6752
|
-
|
6967
|
+
// Setting src through `src` instead of `setSrc` will be deprecated
|
6968
|
+
this.setSrc(src);
|
6753
6969
|
}
|
6754
6970
|
};
|
6971
|
+
|
6972
|
+
vjs.Html5.prototype.setSrc = function(src) {
|
6973
|
+
this.el_.src = src;
|
6974
|
+
};
|
6975
|
+
|
6755
6976
|
vjs.Html5.prototype.load = function(){ this.el_.load(); };
|
6756
6977
|
vjs.Html5.prototype.currentSrc = function(){ return this.el_.currentSrc; };
|
6757
6978
|
|
@@ -6780,10 +7001,13 @@ vjs.Html5.prototype.setPlaybackRate = function(val){ this.el_.playbackRate = val
|
|
6780
7001
|
|
6781
7002
|
vjs.Html5.prototype.networkState = function(){ return this.el_.networkState; };
|
6782
7003
|
|
6783
|
-
/* HTML5 Support Testing ---------------------------------------------------- */
|
6784
7004
|
|
7005
|
+
/**
|
7006
|
+
* Check if HTML5 video is supported by this browser/device
|
7007
|
+
* @return {Boolean}
|
7008
|
+
*/
|
6785
7009
|
vjs.Html5.isSupported = function(){
|
6786
|
-
//
|
7010
|
+
// IE9 with no Media Player is a LIAR! (#984)
|
6787
7011
|
try {
|
6788
7012
|
vjs.TEST_VID['volume'] = 0.5;
|
6789
7013
|
} catch (e) {
|
@@ -6793,31 +7017,119 @@ vjs.Html5.isSupported = function(){
|
|
6793
7017
|
return !!vjs.TEST_VID.canPlayType;
|
6794
7018
|
};
|
6795
7019
|
|
6796
|
-
|
6797
|
-
|
6798
|
-
|
6799
|
-
|
6800
|
-
|
6801
|
-
|
6802
|
-
|
7020
|
+
// Add Source Handler pattern functions to this tech
|
7021
|
+
vjs.MediaTechController.withSourceHandlers(vjs.Html5);
|
7022
|
+
|
7023
|
+
/**
|
7024
|
+
* The default native source handler.
|
7025
|
+
* This simply passes the source to the video element. Nothing fancy.
|
7026
|
+
* @param {Object} source The source object
|
7027
|
+
* @param {vjs.Html5} tech The instance of the HTML5 tech
|
7028
|
+
*/
|
7029
|
+
vjs.Html5.nativeSourceHandler = {};
|
7030
|
+
|
7031
|
+
/**
|
7032
|
+
* Check if the video element can handle the source natively
|
7033
|
+
* @param {Object} source The source object
|
7034
|
+
* @return {String} 'probably', 'maybe', or '' (empty string)
|
7035
|
+
*/
|
7036
|
+
vjs.Html5.nativeSourceHandler.canHandleSource = function(source){
|
7037
|
+
var ext;
|
7038
|
+
|
7039
|
+
function canPlayType(type){
|
7040
|
+
// IE9 on Windows 7 without MediaPlayer throws an error here
|
7041
|
+
// https://github.com/videojs/video.js/issues/519
|
7042
|
+
try {
|
7043
|
+
return !!vjs.TEST_VID.canPlayType(type);
|
7044
|
+
} catch(e) {
|
7045
|
+
return '';
|
7046
|
+
}
|
7047
|
+
}
|
7048
|
+
|
7049
|
+
// If a type was provided we should rely on that
|
7050
|
+
if (source.type) {
|
7051
|
+
return canPlayType(source.type);
|
7052
|
+
} else {
|
7053
|
+
// If no type, fall back to checking 'video/[EXTENSION]'
|
7054
|
+
ext = source.src.match(/\.([^\/\?]+)(\?[^\/]+)?$/i)[1];
|
7055
|
+
return canPlayType('video/'+ext);
|
6803
7056
|
}
|
6804
|
-
// TODO: Check Type
|
6805
|
-
// If no Type, check ext
|
6806
|
-
// Check Media Type
|
6807
7057
|
};
|
6808
7058
|
|
7059
|
+
/**
|
7060
|
+
* Pass the source to the video element
|
7061
|
+
* Adaptive source handlers will have more complicated workflows before passing
|
7062
|
+
* video data to the video element
|
7063
|
+
* @param {Object} source The source object
|
7064
|
+
* @param {vjs.Html5} tech The instance of the Html5 tech
|
7065
|
+
*/
|
7066
|
+
vjs.Html5.nativeSourceHandler.handleSource = function(source, tech){
|
7067
|
+
tech.setSrc(source.src);
|
7068
|
+
};
|
7069
|
+
|
7070
|
+
/**
|
7071
|
+
* Clean up the source handler when disposing the player or switching sources..
|
7072
|
+
* (no cleanup is needed when supporting the format natively)
|
7073
|
+
*/
|
7074
|
+
vjs.Html5.nativeSourceHandler.dispose = function(){};
|
7075
|
+
|
7076
|
+
// Register the native source handler
|
7077
|
+
vjs.Html5.registerSourceHandler(vjs.Html5.nativeSourceHandler);
|
7078
|
+
|
7079
|
+
/**
|
7080
|
+
* Check if the volume can be changed in this browser/device.
|
7081
|
+
* Volume cannot be changed in a lot of mobile devices.
|
7082
|
+
* Specifically, it can't be changed from 1 on iOS.
|
7083
|
+
* @return {Boolean}
|
7084
|
+
*/
|
6809
7085
|
vjs.Html5.canControlVolume = function(){
|
6810
7086
|
var volume = vjs.TEST_VID.volume;
|
6811
7087
|
vjs.TEST_VID.volume = (volume / 2) + 0.1;
|
6812
7088
|
return volume !== vjs.TEST_VID.volume;
|
6813
7089
|
};
|
6814
7090
|
|
7091
|
+
/**
|
7092
|
+
* Check if playbackRate is supported in this browser/device.
|
7093
|
+
* @return {[type]} [description]
|
7094
|
+
*/
|
6815
7095
|
vjs.Html5.canControlPlaybackRate = function(){
|
6816
7096
|
var playbackRate = vjs.TEST_VID.playbackRate;
|
6817
7097
|
vjs.TEST_VID.playbackRate = (playbackRate / 2) + 0.1;
|
6818
7098
|
return playbackRate !== vjs.TEST_VID.playbackRate;
|
6819
7099
|
};
|
6820
7100
|
|
7101
|
+
/**
|
7102
|
+
* Set the tech's volume control support status
|
7103
|
+
* @type {Boolean}
|
7104
|
+
*/
|
7105
|
+
vjs.Html5.prototype['featuresVolumeControl'] = vjs.Html5.canControlVolume();
|
7106
|
+
|
7107
|
+
/**
|
7108
|
+
* Set the tech's playbackRate support status
|
7109
|
+
* @type {Boolean}
|
7110
|
+
*/
|
7111
|
+
vjs.Html5.prototype['featuresPlaybackRate'] = vjs.Html5.canControlPlaybackRate();
|
7112
|
+
|
7113
|
+
/**
|
7114
|
+
* Set the tech's status on moving the video element.
|
7115
|
+
* In iOS, if you move a video element in the DOM, it breaks video playback.
|
7116
|
+
* @type {Boolean}
|
7117
|
+
*/
|
7118
|
+
vjs.Html5.prototype['movingMediaElementInDOM'] = !vjs.IS_IOS;
|
7119
|
+
|
7120
|
+
/**
|
7121
|
+
* Set the the tech's fullscreen resize support status.
|
7122
|
+
* HTML video is able to automatically resize when going to fullscreen.
|
7123
|
+
* (No longer appears to be used. Can probably be removed.)
|
7124
|
+
*/
|
7125
|
+
vjs.Html5.prototype['featuresFullscreenResize'] = true;
|
7126
|
+
|
7127
|
+
/**
|
7128
|
+
* Set the tech's progress event support status
|
7129
|
+
* (this disables the manual progress events of the MediaTechController)
|
7130
|
+
*/
|
7131
|
+
vjs.Html5.prototype['featuresProgressEvents'] = true;
|
7132
|
+
|
6821
7133
|
// HTML5 Feature detection and Device Fixes --------------------------------- //
|
6822
7134
|
(function() {
|
6823
7135
|
var canPlayType,
|
@@ -6959,21 +7271,16 @@ vjs.Flash = vjs.MediaTechController.extend({
|
|
6959
7271
|
// Merge default attributes with ones passed in
|
6960
7272
|
attributes = vjs.obj.merge({
|
6961
7273
|
'id': objId,
|
6962
|
-
'name': objId, // Both ID and Name needed or swf to
|
7274
|
+
'name': objId, // Both ID and Name needed or swf to identify itself
|
6963
7275
|
'class': 'vjs-tech'
|
6964
7276
|
}, options['attributes'])
|
6965
7277
|
;
|
6966
7278
|
|
6967
7279
|
// If source was supplied pass as a flash var.
|
6968
7280
|
if (source) {
|
6969
|
-
|
6970
|
-
|
6971
|
-
|
6972
|
-
flashVars['rtmpStream'] = encodeURIComponent(parts.stream);
|
6973
|
-
}
|
6974
|
-
else {
|
6975
|
-
flashVars['src'] = encodeURIComponent(vjs.getAbsoluteURL(source.src));
|
6976
|
-
}
|
7281
|
+
this.ready(function(){
|
7282
|
+
this.setSource(source);
|
7283
|
+
});
|
6977
7284
|
}
|
6978
7285
|
|
6979
7286
|
// Add placeholder to player div
|
@@ -7025,21 +7332,20 @@ vjs.Flash.prototype.src = function(src){
|
|
7025
7332
|
return this['currentSrc']();
|
7026
7333
|
}
|
7027
7334
|
|
7028
|
-
|
7029
|
-
|
7030
|
-
|
7031
|
-
|
7032
|
-
|
7033
|
-
|
7034
|
-
|
7035
|
-
|
7036
|
-
}
|
7335
|
+
// Setting src through `src` not `setSrc` will be deprecated
|
7336
|
+
return this.setSrc(src);
|
7337
|
+
};
|
7338
|
+
|
7339
|
+
vjs.Flash.prototype.setSrc = function(src){
|
7340
|
+
// Make sure source URL is absolute.
|
7341
|
+
src = vjs.getAbsoluteURL(src);
|
7342
|
+
this.el_.vjs_src(src);
|
7037
7343
|
|
7038
7344
|
// Currently the SWF doesn't autoplay if you load a source later.
|
7039
7345
|
// e.g. Load player w/ no source, wait 2s, set src.
|
7040
7346
|
if (this.player_.autoplay()) {
|
7041
7347
|
var tech = this;
|
7042
|
-
setTimeout(function(){ tech.play(); }, 0);
|
7348
|
+
this.setTimeout(function(){ tech.play(); }, 0);
|
7043
7349
|
}
|
7044
7350
|
};
|
7045
7351
|
|
@@ -7059,17 +7365,11 @@ vjs.Flash.prototype['currentTime'] = function(time){
|
|
7059
7365
|
};
|
7060
7366
|
|
7061
7367
|
vjs.Flash.prototype['currentSrc'] = function(){
|
7062
|
-
|
7063
|
-
|
7064
|
-
|
7065
|
-
|
7066
|
-
stream = this['rtmpStream']();
|
7067
|
-
|
7068
|
-
if (connection && stream) {
|
7069
|
-
src = vjs.Flash.streamFromParts(connection, stream);
|
7070
|
-
}
|
7368
|
+
if (this.currentSource_) {
|
7369
|
+
return this.currentSource_.src;
|
7370
|
+
} else {
|
7371
|
+
return this.el_.vjs_getProperty('currentSrc');
|
7071
7372
|
}
|
7072
|
-
return src;
|
7073
7373
|
};
|
7074
7374
|
|
7075
7375
|
vjs.Flash.prototype.load = function(){
|
@@ -7106,10 +7406,10 @@ vjs.Flash.prototype.enterFullScreen = function(){
|
|
7106
7406
|
function createSetter(attr){
|
7107
7407
|
var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);
|
7108
7408
|
api['set'+attrUpper] = function(val){ return this.el_.vjs_setProperty(attr, val); };
|
7109
|
-
}
|
7409
|
+
}
|
7110
7410
|
function createGetter(attr) {
|
7111
7411
|
api[attr] = function(){ return this.el_.vjs_getProperty(attr); };
|
7112
|
-
}
|
7412
|
+
}
|
7113
7413
|
|
7114
7414
|
// Create getter and setters for all read/write attributes
|
7115
7415
|
for (i = 0; i < readWrite.length; i++) {
|
@@ -7130,19 +7430,59 @@ vjs.Flash.isSupported = function(){
|
|
7130
7430
|
// return swfobject.hasFlashPlayerVersion('10');
|
7131
7431
|
};
|
7132
7432
|
|
7133
|
-
|
7433
|
+
// Add Source Handler pattern functions to this tech
|
7434
|
+
vjs.MediaTechController.withSourceHandlers(vjs.Flash);
|
7435
|
+
|
7436
|
+
/**
|
7437
|
+
* The default native source handler.
|
7438
|
+
* This simply passes the source to the video element. Nothing fancy.
|
7439
|
+
* @param {Object} source The source object
|
7440
|
+
* @param {vjs.Flash} tech The instance of the Flash tech
|
7441
|
+
*/
|
7442
|
+
vjs.Flash.nativeSourceHandler = {};
|
7443
|
+
|
7444
|
+
/**
|
7445
|
+
* Check Flash can handle the source natively
|
7446
|
+
* @param {Object} source The source object
|
7447
|
+
* @return {String} 'probably', 'maybe', or '' (empty string)
|
7448
|
+
*/
|
7449
|
+
vjs.Flash.nativeSourceHandler.canHandleSource = function(source){
|
7134
7450
|
var type;
|
7135
7451
|
|
7136
|
-
if (!
|
7452
|
+
if (!source.type) {
|
7137
7453
|
return '';
|
7138
7454
|
}
|
7139
7455
|
|
7140
|
-
type
|
7141
|
-
|
7456
|
+
// Strip code information from the type because we don't get that specific
|
7457
|
+
type = source.type.replace(/;.*/,'').toLowerCase();
|
7458
|
+
|
7459
|
+
if (type in vjs.Flash.formats) {
|
7142
7460
|
return 'maybe';
|
7143
7461
|
}
|
7462
|
+
|
7463
|
+
return '';
|
7144
7464
|
};
|
7145
7465
|
|
7466
|
+
/**
|
7467
|
+
* Pass the source to the flash object
|
7468
|
+
* Adaptive source handlers will have more complicated workflows before passing
|
7469
|
+
* video data to the video element
|
7470
|
+
* @param {Object} source The source object
|
7471
|
+
* @param {vjs.Flash} tech The instance of the Flash tech
|
7472
|
+
*/
|
7473
|
+
vjs.Flash.nativeSourceHandler.handleSource = function(source, tech){
|
7474
|
+
tech.setSrc(source.src);
|
7475
|
+
};
|
7476
|
+
|
7477
|
+
/**
|
7478
|
+
* Clean up the source handler when disposing the player or switching sources..
|
7479
|
+
* (no cleanup is needed when supporting the format natively)
|
7480
|
+
*/
|
7481
|
+
vjs.Flash.nativeSourceHandler.dispose = function(){};
|
7482
|
+
|
7483
|
+
// Register the native source handler
|
7484
|
+
vjs.Flash.registerSourceHandler(vjs.Flash.nativeSourceHandler);
|
7485
|
+
|
7146
7486
|
vjs.Flash.formats = {
|
7147
7487
|
'video/flv': 'FLV',
|
7148
7488
|
'video/x-flv': 'FLV',
|
@@ -7150,11 +7490,6 @@ vjs.Flash.formats = {
|
|
7150
7490
|
'video/m4v': 'MP4'
|
7151
7491
|
};
|
7152
7492
|
|
7153
|
-
vjs.Flash.streamingFormats = {
|
7154
|
-
'rtmp/mp4': 'MP4',
|
7155
|
-
'rtmp/flv': 'FLV'
|
7156
|
-
};
|
7157
|
-
|
7158
7493
|
vjs.Flash['onReady'] = function(currSwf){
|
7159
7494
|
var el, player;
|
7160
7495
|
|
@@ -7187,7 +7522,7 @@ vjs.Flash['checkReady'] = function(tech){
|
|
7187
7522
|
tech.triggerReady();
|
7188
7523
|
} else {
|
7189
7524
|
// wait longer
|
7190
|
-
setTimeout(function(){
|
7525
|
+
this.setTimeout(function(){
|
7191
7526
|
vjs.Flash['checkReady'](tech);
|
7192
7527
|
}, 50);
|
7193
7528
|
}
|
@@ -7257,7 +7592,7 @@ vjs.Flash.embed = function(swf, placeHolder, flashVars, params, attributes){
|
|
7257
7592
|
|
7258
7593
|
vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
|
7259
7594
|
|
7260
|
-
var objTag = '<object type="application/x-shockwave-flash"',
|
7595
|
+
var objTag = '<object type="application/x-shockwave-flash" ',
|
7261
7596
|
flashVarsString = '',
|
7262
7597
|
paramsString = '',
|
7263
7598
|
attrsString = '';
|
@@ -7299,6 +7634,10 @@ vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){
|
|
7299
7634
|
|
7300
7635
|
return objTag + attrsString + '>' + paramsString + '</object>';
|
7301
7636
|
};
|
7637
|
+
vjs.Flash.streamingFormats = {
|
7638
|
+
'rtmp/mp4': 'MP4',
|
7639
|
+
'rtmp/flv': 'FLV'
|
7640
|
+
};
|
7302
7641
|
|
7303
7642
|
vjs.Flash.streamFromParts = function(connection, stream) {
|
7304
7643
|
return connection + '&' + stream;
|
@@ -7347,6 +7686,42 @@ vjs.Flash.RTMP_RE = /^rtmp[set]?:\/\//i;
|
|
7347
7686
|
vjs.Flash.isStreamingSrc = function(src) {
|
7348
7687
|
return vjs.Flash.RTMP_RE.test(src);
|
7349
7688
|
};
|
7689
|
+
|
7690
|
+
/**
|
7691
|
+
* A source handler for RTMP urls
|
7692
|
+
* @type {Object}
|
7693
|
+
*/
|
7694
|
+
vjs.Flash.rtmpSourceHandler = {};
|
7695
|
+
|
7696
|
+
/**
|
7697
|
+
* Check Flash can handle the source natively
|
7698
|
+
* @param {Object} source The source object
|
7699
|
+
* @return {String} 'probably', 'maybe', or '' (empty string)
|
7700
|
+
*/
|
7701
|
+
vjs.Flash.rtmpSourceHandler.canHandleSource = function(source){
|
7702
|
+
if (vjs.Flash.isStreamingType(source.type) || vjs.Flash.isStreamingSrc(source.src)) {
|
7703
|
+
return 'maybe';
|
7704
|
+
}
|
7705
|
+
|
7706
|
+
return '';
|
7707
|
+
};
|
7708
|
+
|
7709
|
+
/**
|
7710
|
+
* Pass the source to the flash object
|
7711
|
+
* Adaptive source handlers will have more complicated workflows before passing
|
7712
|
+
* video data to the video element
|
7713
|
+
* @param {Object} source The source object
|
7714
|
+
* @param {vjs.Flash} tech The instance of the Flash tech
|
7715
|
+
*/
|
7716
|
+
vjs.Flash.rtmpSourceHandler.handleSource = function(source, tech){
|
7717
|
+
var srcParts = vjs.Flash.streamToParts(source.src);
|
7718
|
+
|
7719
|
+
tech.setRtmpConnection(srcParts.connection);
|
7720
|
+
tech.setRtmpStream(srcParts.stream);
|
7721
|
+
};
|
7722
|
+
|
7723
|
+
// Register the native source handler
|
7724
|
+
vjs.Flash.registerSourceHandler(vjs.Flash.rtmpSourceHandler);
|
7350
7725
|
/**
|
7351
7726
|
* The Media Loader is the component that decides which playback technology to load
|
7352
7727
|
* when the player is initialized.
|
@@ -7383,8 +7758,8 @@ vjs.MediaLoader = vjs.Component.extend({
|
|
7383
7758
|
/**
|
7384
7759
|
* @fileoverview Text Tracks
|
7385
7760
|
* Text tracks are tracks of timed text events.
|
7386
|
-
* Captions - text displayed over the video for the hearing
|
7387
|
-
* Subtitles - text displayed over the video for those who don't understand
|
7761
|
+
* Captions - text displayed over the video for the hearing impaired
|
7762
|
+
* Subtitles - text displayed over the video for those who don't understand language in the video
|
7388
7763
|
* Chapters - text displayed in a menu allowing the user to jump to particular points (chapters) in the video
|
7389
7764
|
* Descriptions (not supported yet) - audio descriptions that are read back to the user by a screen reading device
|
7390
7765
|
*/
|
@@ -7437,14 +7812,14 @@ vjs.Player.prototype.addTextTrack = function(kind, label, language, options){
|
|
7437
7812
|
tracks.push(track);
|
7438
7813
|
|
7439
7814
|
// If track.dflt() is set, start showing immediately
|
7440
|
-
// TODO: Add a process to
|
7441
|
-
//
|
7815
|
+
// TODO: Add a process to determine the best track to show for the specific kind
|
7816
|
+
// In case there are multiple defaulted tracks of the same kind
|
7442
7817
|
// Or the user has a set preference of a specific language that should override the default
|
7443
7818
|
// Note: The setTimeout is a workaround because with the html5 tech, the player is 'ready'
|
7444
7819
|
// before it's child components (including the textTrackDisplay) have finished loading.
|
7445
7820
|
if (track.dflt()) {
|
7446
7821
|
this.ready(function(){
|
7447
|
-
setTimeout(function(){
|
7822
|
+
this.setTimeout(function(){
|
7448
7823
|
track.player().showTextTrack(track.id());
|
7449
7824
|
}, 0);
|
7450
7825
|
});
|
@@ -7531,6 +7906,8 @@ vjs.TextTrack = vjs.Component.extend({
|
|
7531
7906
|
this.activeCues_ = [];
|
7532
7907
|
this.readyState_ = 0;
|
7533
7908
|
this.mode_ = 0;
|
7909
|
+
|
7910
|
+
player.on('dispose', vjs.bind(this, this.deactivate, this.id_));
|
7534
7911
|
}
|
7535
7912
|
});
|
7536
7913
|
|
@@ -7804,7 +8181,13 @@ vjs.TextTrack.prototype.load = function(){
|
|
7804
8181
|
// Only load if not loaded yet.
|
7805
8182
|
if (this.readyState_ === 0) {
|
7806
8183
|
this.readyState_ = 1;
|
7807
|
-
vjs.
|
8184
|
+
vjs.xhr(this.src_, vjs.bind(function(err, response, responseBody){
|
8185
|
+
if (err) {
|
8186
|
+
return this.onError(err);
|
8187
|
+
}
|
8188
|
+
|
8189
|
+
this.parseCues(responseBody);
|
8190
|
+
}));
|
7808
8191
|
}
|
7809
8192
|
|
7810
8193
|
};
|
@@ -7854,7 +8237,7 @@ vjs.TextTrack.prototype.parseCues = function(srcContent) {
|
|
7854
8237
|
text = [];
|
7855
8238
|
|
7856
8239
|
// Loop until a blank line or end of lines
|
7857
|
-
//
|
8240
|
+
// Assuming trim('') returns false for blank lines
|
7858
8241
|
while (lines[++i] && (line = vjs.trim(lines[i]))) {
|
7859
8242
|
text.push(line);
|
7860
8243
|
}
|