Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing a Source Handlers interface for supporting adaptive formats #1560

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build/source-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var sourceFiles = [
"src/js/core-object.js",
"src/js/events.js",
"src/js/lib.js",
"src/js/xhr.js",
"src/js/util.js",
"src/js/component.js",
"src/js/button.js",
Expand All @@ -44,6 +45,7 @@ var sourceFiles = [
"src/js/media/media.js",
"src/js/media/html5.js",
"src/js/media/flash.js",
"src/js/media/flash.rtmp.js",
"src/js/media/loader.js",
"src/js/tracks.js",
"src/js/json.js",
Expand Down
80 changes: 0 additions & 80 deletions src/js/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -614,86 +614,6 @@ vjs.createTimeRange = function(start, end){
};
};

/**
* Simple http request for retrieving external files (e.g. text tracks)
* @param {String} url URL of resource
* @param {Function} onSuccess Success callback
* @param {Function=} onError Error callback
* @param {Boolean=} withCredentials Flag which allow credentials
* @private
*/
vjs.get = function(url, onSuccess, onError, withCredentials){
var fileUrl, request, urlInfo, winLoc, crossOrigin;

onError = onError || function(){};

if (typeof XMLHttpRequest === 'undefined') {
// Shim XMLHttpRequest for older IEs
window.XMLHttpRequest = function () {
try { return new window.ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch (e) {}
try { return new window.ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch (f) {}
try { return new window.ActiveXObject('Msxml2.XMLHTTP'); } catch (g) {}
throw new Error('This browser does not support XMLHttpRequest.');
};
}

request = new XMLHttpRequest();

urlInfo = vjs.parseUrl(url);
winLoc = window.location;
// check if url is for another domain/origin
// ie8 doesn't know location.origin, so we won't rely on it here
crossOrigin = (urlInfo.protocol + urlInfo.host) !== (winLoc.protocol + winLoc.host);

// Use XDomainRequest for IE if XMLHTTPRequest2 isn't available
// 'withCredentials' is only available in XMLHTTPRequest2
// Also XDomainRequest has a lot of gotchas, so only use if cross domain
if(crossOrigin && window.XDomainRequest && !('withCredentials' in request)) {
request = new window.XDomainRequest();
request.onload = function() {
onSuccess(request.responseText);
};
request.onerror = onError;
// these blank handlers need to be set to fix ie9 http://cypressnorth.com/programming/internet-explorer-aborting-ajax-requests-fixed/
request.onprogress = function() {};
request.ontimeout = onError;

// XMLHTTPRequest
} else {
fileUrl = (urlInfo.protocol == 'file:' || winLoc.protocol == 'file:');

request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200 || fileUrl && request.status === 0) {
onSuccess(request.responseText);
} else {
onError(request.responseText);
}
}
};
}

// open the connection
try {
// Third arg is async, or ignored by XDomainRequest
request.open('GET', url, true);
// withCredentials only supported by XMLHttpRequest2
if(withCredentials) {
request.withCredentials = true;
}
} catch(e) {
onError(e);
return;
}

// send the request
try {
request.send();
} catch(e) {
onError(e);
}
};

/**
* Add to local storage (may removable)
* @private
Expand Down
143 changes: 59 additions & 84 deletions src/js/media/flash.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,9 @@ vjs.Flash = vjs.MediaTechController.extend({

// If source was supplied pass as a flash var.
if (source) {
if (source.type && vjs.Flash.isStreamingType(source.type)) {
var parts = vjs.Flash.streamToParts(source.src);
flashVars['rtmpConnection'] = encodeURIComponent(parts.connection);
flashVars['rtmpStream'] = encodeURIComponent(parts.stream);
}
else {
flashVars['src'] = encodeURIComponent(vjs.getAbsoluteURL(source.src));
}
this.ready(function(){
this.setSource(source);
});
}

// Add placeholder to player div
Expand Down Expand Up @@ -124,15 +119,14 @@ vjs.Flash.prototype.src = function(src){
return this['currentSrc']();
}

if (vjs.Flash.isStreamingSrc(src)) {
src = vjs.Flash.streamToParts(src);
this.setRtmpConnection(src.connection);
this.setRtmpStream(src.stream);
} else {
// Make sure source URL is absolute.
src = vjs.getAbsoluteURL(src);
this.el_.vjs_src(src);
}
// Setting src through `src` not `setSrc` will be deprecated
return this.setSrc(src);
};

vjs.Flash.prototype.setSrc = function(src){
// Make sure source URL is absolute.
src = vjs.getAbsoluteURL(src);
this.el_.vjs_src(src);

// Currently the SWF doesn't autoplay if you load a source later.
// e.g. Load player w/ no source, wait 2s, set src.
Expand All @@ -158,17 +152,11 @@ vjs.Flash.prototype['currentTime'] = function(time){
};

vjs.Flash.prototype['currentSrc'] = function(){
var src = this.el_.vjs_getProperty('currentSrc');
// no src, check and see if RTMP
if (src == null) {
var connection = this['rtmpConnection'](),
stream = this['rtmpStream']();

if (connection && stream) {
src = vjs.Flash.streamFromParts(connection, stream);
}
if (this.currentSource_) {
return this.currentSource_.src;
} else {
return this.el_.vjs_getProperty('currentSrc');
}
return src;
};

vjs.Flash.prototype.load = function(){
Expand Down Expand Up @@ -229,31 +217,66 @@ vjs.Flash.isSupported = function(){
// return swfobject.hasFlashPlayerVersion('10');
};

vjs.Flash.canPlaySource = function(srcObj){
// Add Source Handler pattern functions to this tech
vjs.MediaTechController.withSourceHandlers(vjs.Flash);

/**
* The default native source handler.
* This simply passes the source to the video element. Nothing fancy.
* @param {Object} source The source object
* @param {vjs.Flash} tech The instance of the Flash tech
*/
vjs.Flash.nativeSourceHandler = {};

/**
* Check Flash can handle the source natively
* @param {Object} source The source object
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
vjs.Flash.nativeSourceHandler.canHandleSource = function(source){
var type;

if (!srcObj.type) {
if (!source.type) {
return '';
}

type = srcObj.type.replace(/;.*/,'').toLowerCase();
if (type in vjs.Flash.formats || type in vjs.Flash.streamingFormats) {
// Strip code information from the type because we don't get that specific
type = source.type.replace(/;.*/,'').toLowerCase();

if (type in vjs.Flash.formats) {
return 'maybe';
}

return '';
};

/**
* Pass the source to the flash object
* Adaptive source handlers will have more complicated workflows before passing
* video data to the video element
* @param {Object} source The source object
* @param {vjs.Flash} tech The instance of the Flash tech
*/
vjs.Flash.nativeSourceHandler.handleSource = function(source, tech){
tech.setSrc(source.src);
};

/**
* Clean up the source handler when disposing the player or switching sources..
* (no cleanup is needed when supporting the format natively)
*/
vjs.Flash.nativeSourceHandler.dispose = function(){};

// Register the native source handler
vjs.Flash.registerSourceHandler(vjs.Flash.nativeSourceHandler);

vjs.Flash.formats = {
'video/flv': 'FLV',
'video/x-flv': 'FLV',
'video/mp4': 'MP4',
'video/m4v': 'MP4'
};

vjs.Flash.streamingFormats = {
'rtmp/mp4': 'MP4',
'rtmp/flv': 'FLV'
};

vjs.Flash['onReady'] = function(currSwf){
var el, player;

Expand Down Expand Up @@ -398,51 +421,3 @@ vjs.Flash.getEmbedCode = function(swf, flashVars, params, attributes){

return objTag + attrsString + '>' + paramsString + '</object>';
};

vjs.Flash.streamFromParts = function(connection, stream) {
return connection + '&' + stream;
};

vjs.Flash.streamToParts = function(src) {
var parts = {
connection: '',
stream: ''
};

if (! src) {
return parts;
}

// Look for the normal URL separator we expect, '&'.
// If found, we split the URL into two pieces around the
// first '&'.
var connEnd = src.indexOf('&');
var streamBegin;
if (connEnd !== -1) {
streamBegin = connEnd + 1;
}
else {
// If there's not a '&', we use the last '/' as the delimiter.
connEnd = streamBegin = src.lastIndexOf('/') + 1;
if (connEnd === 0) {
// really, there's not a '/'?
connEnd = streamBegin = src.length;
}
}
parts.connection = src.substring(0, connEnd);
parts.stream = src.substring(streamBegin, src.length);

return parts;
};

vjs.Flash.isStreamingType = function(srcType) {
return srcType in vjs.Flash.streamingFormats;
};

// RTMP has four variations, any string starting
// with one of these protocols should be valid
vjs.Flash.RTMP_RE = /^rtmp[set]?:\/\//i;

vjs.Flash.isStreamingSrc = function(src) {
return vjs.Flash.RTMP_RE.test(src);
};
88 changes: 88 additions & 0 deletions src/js/media/flash.rtmp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
vjs.Flash.streamingFormats = {
'rtmp/mp4': 'MP4',
'rtmp/flv': 'FLV'
};

vjs.Flash.streamFromParts = function(connection, stream) {
return connection + '&' + stream;
};

vjs.Flash.streamToParts = function(src) {
var parts = {
connection: '',
stream: ''
};

if (! src) {
return parts;
}

// Look for the normal URL separator we expect, '&'.
// If found, we split the URL into two pieces around the
// first '&'.
var connEnd = src.indexOf('&');
var streamBegin;
if (connEnd !== -1) {
streamBegin = connEnd + 1;
}
else {
// If there's not a '&', we use the last '/' as the delimiter.
connEnd = streamBegin = src.lastIndexOf('/') + 1;
if (connEnd === 0) {
// really, there's not a '/'?
connEnd = streamBegin = src.length;
}
}
parts.connection = src.substring(0, connEnd);
parts.stream = src.substring(streamBegin, src.length);

return parts;
};

vjs.Flash.isStreamingType = function(srcType) {
return srcType in vjs.Flash.streamingFormats;
};

// RTMP has four variations, any string starting
// with one of these protocols should be valid
vjs.Flash.RTMP_RE = /^rtmp[set]?:\/\//i;

vjs.Flash.isStreamingSrc = function(src) {
return vjs.Flash.RTMP_RE.test(src);
};

/**
* A source handler for RTMP urls
* @type {Object}
*/
vjs.Flash.rtmpSourceHandler = {};

/**
* Check Flash can handle the source natively
* @param {Object} source The source object
* @return {String} 'probably', 'maybe', or '' (empty string)
*/
vjs.Flash.rtmpSourceHandler.canHandleSource = function(source){
if (vjs.Flash.isStreamingType(source.type) || vjs.Flash.isStreamingSrc(source.src)) {
return 'maybe';
}

return '';
};

/**
* Pass the source to the flash object
* Adaptive source handlers will have more complicated workflows before passing
* video data to the video element
* @param {Object} source The source object
* @param {vjs.Flash} tech The instance of the Flash tech
*/
vjs.Flash.rtmpSourceHandler.handleSource = function(source, tech){
var srcParts = vjs.Flash.streamToParts(source.src);

tech.setRtmpConnection(srcParts.connection);
tech.setRtmpStream(srcParts.stream);
};

// Register the native source handler
vjs.Flash.registerSourceHandler(vjs.Flash.rtmpSourceHandler);
Loading