videojs_rails 4.10.2 → 4.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|