2f979027 by David LaPalomento

Try a whole bunch of places to figure out if the HLS plugin should activate

Instead of only supporting the src attribute, check options.sources for HLS on init. This means re-implementing something that looks a lot like video.js's source selection algorithm. That's another reason to consider converting this plugin into a tech but I'm deferring that for now.
1 parent 16b9cb9d
......@@ -42,8 +42,10 @@
class="video-js vjs-default-skin"
height="300"
width="600"
src="http://solutions.brightcove.com/jwhisenant/hls/apple/bipbop/bipbopall.m3u8"
controls>
<source
src="http://solutions.brightcove.com/jwhisenant/hls/apple/bipbop/bipbopall.m3u8"
type="application/x-mpegURL">
</video>
<script>
videojs.options.flash.swf = 'node_modules/video.js/dist/video-js/video-js.swf';
......
......@@ -182,7 +182,6 @@ var
mediaSource = new videojs.MediaSource(),
segmentParser = new videojs.hls.SegmentParser(),
player = this,
currentSrc,
extname,
srcUrl,
......@@ -195,23 +194,60 @@ var
return;
}
currentSrc = player.currentSrc();
// when the video element is initializing, currentSrc may be undefined
// grab the src from the video element because video.js doesn't currently
// expose it
if (!currentSrc) {
currentSrc = player.el().querySelector('.vjs-tech').src;
}
srcUrl = (function() {
var
extname,
i = 0,
j = 0,
src = player.el().querySelector('.vjs-tech').src,
sources = player.options().sources,
techName,
length = sources.length;
// use the URL specified in options if one was provided
if (typeof options === 'string') {
return options;
} else if (options) {
return options.url;
}
extname = (/[^#?]*(?:\/[^#?]*\.([^#?]*))/).exec(currentSrc);
if (typeof options === 'string') {
srcUrl = options;
} else if (options) {
srcUrl = options.url;
} else if (extname && extname[1] === 'm3u8') {
// if the currentSrc looks like an m3u8, attempt to use it
srcUrl = currentSrc;
} else {
// src attributes take precedence over source children
if (src) {
// assume files with the m3u8 extension are HLS
extname = (/[^#?]*(?:\/[^#?]*\.([^#?]*))/).exec(src);
if (extname && extname[1] === 'm3u8') {
return src;
}
return;
}
// find the first playable source
for (; i < length; i++) {
// ignore sources without a specified type
if (!sources[i].type) {
continue;
}
// do nothing if the source is handled by one of the standard techs
for (j in player.options().techOrder) {
techName = player.options().techOrder[j];
techName = techName[0].toUpperCase() + techName.substring(1);
if (videojs[techName].canPlaySource({ type: sources[i].type })) {
return;
}
}
// use the plugin if the MIME type specifies HLS
if ((/application\/x-mpegURL/).test(sources[i].type) ||
(/application\/vnd\.apple\.mpegURL/).test(sources[i].type)) {
return sources[i].src;
}
}
})();
if (!srcUrl) {
// do nothing until the plugin is initialized with a valid URL
videojs.log('hls: no valid playlist URL specified');
return;
......@@ -546,10 +582,10 @@ var
player.hls.mediaIndex = 0;
downloadPlaylist(srcUrl);
});
player.src({
player.src([{
src: videojs.URL.createObjectURL(mediaSource),
type: "video/flv"
});
}]);
};
videojs.plugin('hls', function() {
......
......@@ -506,9 +506,9 @@ test('only makes one segment request at a time', function() {
strictEqual(1, openedXhrs, 'only one XHR is made');
});
test('uses the currentSrc if no options are provided and it ends in ".m3u8"', function() {
test('uses the src attribute if no options are provided and it ends in ".m3u8"', function() {
var url = 'http://example.com/services/mobile/streaming/index/master.m3u8?videoId=1824650741001';
player.src(url);
player.el().querySelector('.vjs-tech').src = url;
player.hls();
videojs.mediaSources[player.currentSrc()].trigger({
type: 'sourceopen'
......@@ -517,33 +517,53 @@ test('uses the currentSrc if no options are provided and it ends in ".m3u8"', fu
strictEqual(url, xhrUrls[0], 'currentSrc is used');
});
test('ignores currentSrc if it doesn\'t have the "m3u8" extension', function() {
player.src('basdfasdfasdfliel//.m3u9');
test('ignores src attribute if it doesn\'t have the "m3u8" extension', function() {
var tech = player.el().querySelector('.vjs-tech');
tech.src = 'basdfasdfasdfliel//.m3u9';
player.hls();
ok(!(player.currentSrc() in videojs.mediaSources), 'no media source is created');
strictEqual(xhrUrls.length, 0, 'no request is made');
player.src('');
tech.src = '';
player.hls();
ok(!(player.currentSrc() in videojs.mediaSources), 'no media source is created');
strictEqual(xhrUrls.length, 0, 'no request is made');
player.src('http://example.com/movie.mp4?q=why.m3u8');
tech.src = 'http://example.com/movie.mp4?q=why.m3u8';
player.hls();
ok(!(player.currentSrc() in videojs.mediaSources), 'no media source is created');
strictEqual(xhrUrls.length, 0, 'no request is made');
player.src('http://example.m3u8/movie.mp4');
tech.src = 'http://example.m3u8/movie.mp4';
player.hls();
ok(!(player.currentSrc() in videojs.mediaSources), 'no media source is created');
strictEqual(xhrUrls.length, 0, 'no request is made');
player.src('//example.com/movie.mp4#http://tricky.com/master.m3u8');
tech.src = '//example.com/movie.mp4#http://tricky.com/master.m3u8';
player.hls();
ok(!(player.currentSrc() in videojs.mediaSources), 'no media source is created');
strictEqual(xhrUrls.length, 0, 'no request is made');
});
test('activates if the first playable source is HLS', function() {
document.querySelector('#qunit-fixture').innerHTML =
'<video controls>' +
'<source type="slartibartfast$%" src="movie.slarti">' +
'<source type="application/x-mpegURL" src="movie.m3u8">' +
'<source type="video/mp4" src="movie.mp4">' +
'</video>';
video = document.querySelector('#qunit-fixture video');
player = videojs(video, {
flash: {
swf: '../node_modules/video.js/dist/video-js/video-js.swf'
},
techOrder: ['flash']
});
player.hls();
ok(player.currentSrc() in videojs.mediaSources, 'media source created');
});
test('cancels outstanding XHRs when seeking', function() {
var
aborted = false,
......