Detecting browser compatibility for HTML5 video and audio

Introduction

During the recent redevelopment of the Nomensa Accessible Media Player we decided to add optional HTML5 video support for clients using the JWPlayer. It is currently not possible to generate different types of media players (Flash/html5) through many 3rd party vendors JavaScript APIs. However, since we work with the JWPlayer locally we should be able to implement an HTML5 media player for browsers that support and can play the most common types of media.

It is worthwhile mentioning that videos on the Nomensa blog make use of the YouTube player. As such, HTML5 video will not be available on the blog until such a time as YouTube make it possible to generate HTML5 video output using their JavaScript API.

Different browsers offer different levels of support for HTML5 audio and video. Where some browsers support one type of media file other browsers will fail to do so. While browser vendors continue to implement HTML5 features support should get better and better. However, the situation at the time of writing dictates that we cannot (and certainly should not) assume that a browser will play HTML5 media. We have to think about older browsers as well right? Thankfully the JavaScript API for HTML5 media elements provides a couple of useful methods for determining if a particular browser is likely to be able to play a given file. However, the method requires us to know the mime type and which codecs are required to play the file before it can be used (please refer to the W3C HTML 5 Video Specification for more information on Mime types and codecs).

Determining the Mime type

In our instance we decided that there were sufficiently few types of media supported by JWPlayer that we could determine the mime type and required codecs based on the extension of the file. Consider the code example below (Not all supported file types shown).

var get_mime = function(filetype){
var mimetype = '';
var media_container = 'video';
switch(filetype){
case 'mp4':
mimetype = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
break;
case 'ogg':
mimetype = 'video/ogg; codecs="theora, vorbis"';
break;
case 'webm':
mimetype = 'video/webm; codecs="vp8, vorbis"';
break;
case 'mp3':
mimetype = 'audio/mpeg';
media_container = 'audio';
break;
}
return {'mimetype':mimetype,'container':media_container};
};

The argument to the function (‘filetype’) should be a string containing the file extension without the leading dot. Based on this we are manually setting the mime type, required codecs and the element type before returning the information wrapped up inside a JavaScript object. With this information we can now determine if the users browser is likely to be able to play the media natively or not.

Detecting Browser Support

Once we have information about a media files mime type and HTML element name we can easily determine if the browser is likely to be able to play the media. Consider the following code snippet.

var supports_media = function(mimetype, container) {
var elem = document.createElement(container);
if(typeof elem.canPlayType == ‘function’){
var playable = elem.canPlayType(mimetype);
if((playable.toLowerCase() == 'maybe')||(playable.toLowerCase() == 'probably')){
return true;
}
}
return false;
};

The two arguments to this function are as follows:

  • Mimetype – The mime type and required codecs as a string e.g. 'video/webm; codecs="vp8, vorbis"'
  • Container – The HTML element name expressed as a string e.g. ‘audio’ or ‘video’.

With these parameters we are able to construct an HTML5 <audio> or <video> element using JavaScript and hold it in memory. Once we have this element in memory we can check to see if it contains the canPlayType method (if(typeof elem.canPlayType == ‘function’){}). If the canPlayType method exists on our HTML element we know that the browser in use has some degree of HTML5 media support built into it. Using feature detection (as above) is the preferred way of testing compatibility. If the method is present we know that HTML5 has some degree of support, if not we cannot use HTML5 and must use Flash instead. Simple really! This is preferable to using browser sniffing to determine whether or not HTML5 is supported (see future proofing javascript libraries for more information). The canPlayType method takes the mime-type/required codec string as its only parameter (playable = elem.canPlayType(mimetype);) and returns another string determining the likelihood that the browser will be able to play the file. At the time of writing there the method is likely to one of three strings:

  1. “” an empty string (a negative response);
  2. “maybe”;
  3. “probably”.

If a browser is sure it can play a media file it should return a status of “probably”. If the browser definitely cannot play the file the method should return an empty string. All other results should be denoted by the “maybe” response code. In our instance we decided that we would attempt to play any media that the browser thinks it might be able to handle.

Bringing it all together

Now that we have our two functions for determining if a browser will be able to play a given media file we can use them to determine whether or not to serve up an HTML5 player or a Flash based one for older browsers (See code example below).

Code Example

// Define the get_mime function
var get_mime = function(filetype){
var mimetype = '';
var media_container = 'video';
switch(filetype){
case 'mp4':
mimetype = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
break;
case 'ogg':
mimetype = 'video/ogg; codecs="theora, vorbis"';
break;
case 'webm':
mimetype = 'video/webm; codecs="vp8, vorbis"';
break;
case 'mp3':
mimetype = 'audio/mpeg';
media_container = 'audio';
break;
}
return {'mimetype':mimetype,'container':media_container};
};

// Check to see if the browser can render the file type
// using HTML5
var supports_media = function(mimetype, container) {
var elem = document.createElement(container);
if(typeof elem.canPlayType == ‘function’){
var playable = elem.canPlayType(mimetype);
if((playable.toLowerCase() == 'maybe')||(playable.toLowerCase() == 'probably')){
return true;
}
}
return false;
};

// When the DOM has loaded check the file extension of each media link
// and serve up appropriate media player
$(document).ready(function(){
$(‘a.youtube-links’).each(function(){

var path = $(this).attr(‘href’);

var extension = path.substring(path.lastIndexOf('.') + 1);

var extension_info = get_mime(extension);

if(supports_media(extension_info.mimetype, extension_info.container)){

// Serve up an HTML5 Media Player and controls

serve_html5();

}else{

// Serve up a flash based video for browsers that

//will not play the file using HTML5

serve_flash();

}

});
});

Conclusion

What I hope to have shown is that it should be possible to provide video on the Internet in such a way that it is usable on a fairly wide range of different browsers, technologies and operating systems. With the rise in popularity of devices such as the iPhone and iPad (which will not natively play Flash) it makes sense to provide HTML5 media for browsers that support it, falling back to Flash media players for those that do not. Devices (such as the iPad) that do not support Flash have a fairly good level of support for HTML5 media. As such, by using HTML5 media detection to serve up video and audio content in a suitable manner will help you to extend the reach of multimedia content.

Further reading

 

Start building accessibility into your projects at the beginning to save time and money, don’t just leave it hanging on the backlog letting it gather up dust. Drill it in.

If you would like Nomensa to help you with your accessibility challenges or to provide you with an accessibility evaluation of your website/mobile app, please don’t hesitate to get in touch.

You can give us a call on +44 (0) 117 929 7333 or submit this short form. In the meantime, take a full look at the digital accessibility services that we offer.