diff --git a/src/js/media/html5.js b/src/js/media/html5.js index f4e586762..54a4bfc2e 100644 --- a/src/js/media/html5.js +++ b/src/js/media/html5.js @@ -266,6 +266,55 @@ vjs.Html5.canControlVolume = function(){ return volume !== vjs.TEST_VID.volume; }; +// HTML5 Feature detection and Device Fixes --------------------------------- // +(function() { + var canPlayType, + mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl$/i, + mp4RE = /^video\/mp4$/i; + + vjs.Html5.patchCanPlayType = function() { + // Android 4.0 and above can play HLS to some extent but it reports being unable to do so + if (vjs.ANDROID_VERSION >= 4.0) { + if (!canPlayType) { + canPlayType = HTMLVideoElement.prototype.canPlayType; + } + + HTMLVideoElement.prototype.canPlayType = function(type) { + if (type && mpegurlRE.test(type)) { + return "maybe"; + } + return canPlayType.call(this, type); + }; + } + + // Override Android 2.2 and less canPlayType method which is broken + if (vjs.IS_OLD_ANDROID) { + if (!canPlayType) { + canPlayType = HTMLVideoElement.prototype.canPlayType; + } + + HTMLVideoElement.prototype.canPlayType = function(type){ + if (type && mp4RE.test(type)) { + return "maybe"; + } + return canPlayType.call(this, type); + }; + } + }; + + vjs.Html5.unpatchCanPlayType = function() { + var r = canPlayType; + if (canPlayType) { + HTMLVideoElement.prototype.canPlayType = canPlayType; + canPlayType = null; + return r; + } + }; + + // by default, patch the video element + vjs.Html5.patchCanPlayType(); +})(); + // List of all HTML5 events (various uses). vjs.Html5.Events = 'loadstart,suspend,abort,error,emptied,stalled,loadedmetadata,loadeddata,canplay,canplaythrough,playing,waiting,seeking,seeked,ended,durationchange,timeupdate,progress,play,pause,ratechange,volumechange'.split(','); @@ -300,27 +349,3 @@ vjs.Html5.disposeMediaElement = function(el){ })(); } }; - -// HTML5 Feature detection and Device Fixes --------------------------------- // - -// Android 4.0 and above can play HLS to some extent but it reports being unable to do so -if (vjs.ANDROID_VERSION >= 4.0) { - (function() { - var canPlayType = HTMLVideoElement.prototype.canPlayType, - mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl$/i; - - HTMLVideoElement.prototype.canPlayType = function(type) { - if (type && mpegurlRE.test(type)) { - return "maybe"; - } - return canPlayType.call(video.constructor.prototype, type); - } - })(); -} - - // Override Android 2.2 and less canPlayType method which is broken -if (vjs.IS_OLD_ANDROID) { - document.createElement('video').constructor.prototype.canPlayType = function(type){ - return (type && type.toLowerCase().indexOf('video/mp4') != -1) ? 'maybe' : ''; - }; -} diff --git a/test/unit/media.html5.js b/test/unit/media.html5.js index e38777ea0..d828a5aa2 100644 --- a/test/unit/media.html5.js +++ b/test/unit/media.html5.js @@ -1,5 +1,7 @@ module('HTML5'); +var oldAndroidVersion; + test('should detect whether the volume can be changed', function(){ var testVid, ConstVolumeVideo; if (!{}['__defineSetter__']) { @@ -38,3 +40,50 @@ test('should re-link the player if the tech is moved', function(){ strictEqual(player, tech.el()['player']); }); + +test('patchCanPlayType patches canplaytype with our function, conditionally', function() { + var oldAV = vjs.ANDROID_VERSION, + video = document.createElement('video'), + canPlayType = HTMLVideoElement.prototype.canPlayType, + patchCanPlayType, + unpatchedCanPlayType; + + vjs.ANDROID_VERSION = 4.0 + vjs.Html5.patchCanPlayType(); + + notStrictEqual(video.canPlayType, canPlayType, 'original canPlayType and patched canPlayType should not be equal'); + + patchCanPlayType = video.canPlayType; + unpatchedCanPlayType = vjs.Html5.unpatchCanPlayType(); + + strictEqual(video.canPlayType, HTMLVideoElement.prototype.canPlayType, 'original canPlayType and unpatched canPlayType should be equal'); + + vjs.ANDROID_VERSION = oldAV; +}); + +test('should return maybe for HLS urls on Android 4.0 or above', function() { + var oldAV = vjs.ANDROID_VERSION, + video = document.createElement('video'); + + vjs.ANDROID_VERSION = 4.0 + vjs.Html5.patchCanPlayType(); + + strictEqual(video.canPlayType('application/x-mpegurl'), "maybe", "android version 4.0 or above should be a maybe for x-mpegurl"); + strictEqual(video.canPlayType('application/x-mpegURL'), "maybe", "android version 4.0 or above should be a maybe for x-mpegURL"); + strictEqual(video.canPlayType('application/vnd.apple.mpegurl'), "maybe", "android version 4.0 or above should be a maybe for vnd.apple.mpegurl"); + strictEqual(video.canPlayType('application/vnd.apple.mpegURL'), "maybe", "android version 4.0 or above should be a maybe for vnd.apple.mpegurl"); + + vjs.ANDROID_VERSION = oldAV; +}); + +test('should return a maybe for mp4 on OLD ANDROID', function() { + var isOldAndroid = vjs.IS_OLD_ANDROID, + video = document.createElement('video'); + + vjs.IS_OLD_ANDROID = true; + vjs.Html5.patchCanPlayType(); + + strictEqual(video.canPlayType('video/mp4'), 'maybe', 'old android should return a maybe for video/mp4'); + + vjs.IS_OLD_ANDROID = isOldAndroid; +});