diff --git a/src/js/media/html5.js b/src/js/media/html5.js
index 3f36e2e186..af20e7f8b5 100644
--- a/src/js/media/html5.js
+++ b/src/js/media/html5.js
@@ -266,6 +266,53 @@ 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 = vjs.TEST_VID.constructor.prototype.canPlayType;
+ }
+
+ vjs.TEST_VID.constructor.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 = vjs.TEST_VID.constructor.prototype.canPlayType;
+ }
+
+ vjs.TEST_VID.constructor.prototype.canPlayType = function(type){
+ if (type && mp4RE.test(type)) {
+ return "maybe";
+ }
+ return canPlayType.call(this, type);
+ };
+ }
+ };
+
+ vjs.Html5.unpatchCanPlayType = function() {
+ var r = vjs.TEST_VID.constructor.prototype.canPlayType;
+ vjs.TEST_VID.constructor.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,12 +347,3 @@ vjs.Html5.disposeMediaElement = function(el){
})();
}
};
-
-// HTML5 Feature detection and Device Fixes --------------------------------- //
-
- // 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 e38777ea0c..082f3718df 100644
--- a/test/unit/media.html5.js
+++ b/test/unit/media.html5.js
@@ -38,3 +38,59 @@ test('should re-link the player if the tech is moved', function(){
strictEqual(player, tech.el()['player']);
});
+
+test('patchCanPlayType and unpatchCanPlayType are available on Html5 object', function() {
+ ok(vjs.Html5.patchCanPlayType, 'patchCanPlayType is available');
+ ok(vjs.Html5.unpatchCanPlayType, 'unpatchCanPlayType is available');
+});
+
+test('patchCanPlayType patches canplaytype with our function, conditionally', function() {
+ var oldAV = vjs.ANDROID_VERSION,
+ video = document.createElement('video'),
+ canPlayType = vjs.TEST_VID.constructor.prototype.canPlayType,
+ patchedCanPlayType,
+ unpatchedCanPlayType;
+
+ vjs.ANDROID_VERSION = 4.0;
+ vjs.Html5.patchCanPlayType();
+
+ notStrictEqual(video.canPlayType, canPlayType, 'original canPlayType and patched canPlayType should not be equal');
+
+ patchedCanPlayType = video.canPlayType;
+ unpatchedCanPlayType = vjs.Html5.unpatchCanPlayType();
+
+ strictEqual(canPlayType, vjs.TEST_VID.constructor.prototype.canPlayType, 'original canPlayType and unpatched canPlayType should be equal');
+ strictEqual(patchedCanPlayType, unpatchedCanPlayType, 'patched canPlayType and function returned from unpatch are equal');
+
+ vjs.ANDROID_VERSION = oldAV;
+ vjs.Html5.unpatchCanPlayType();
+});
+
+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;
+ vjs.Html5.unpatchCanPlayType();
+});
+
+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;
+ vjs.Html5.unpatchCanPlayType();
+});