Simple Cross-Browser HTML5 video with a single H.264 file and fallback options

June 6, 2010 | JavaScript, Video | 8 Comments

At first glance, the promise of HTML5 <video> seems awesome. Just a simple

<video src="myvideo.mp4" controls></video>

and you’re done right? Not quite. In reality there are all kinds of browser inconsistence that make this impossible. Here’s a run down of the problems:

1. Older browsers don’t support <video>

Only the most recent versions of the big five (Firefox, Chrome, Safari, IE, Opera) support <video>, so you have to have a fallback solution of some kind if you want to use <video> and still support your audience.

2. Newer browsers don’t support the same codecs

Sadly, different browsers support different codecs. H.264 works in Chrome, Safari, and IE9, while Firefox and Opera only support Ogg/Vorbis. All the major browser vendors have pledged support for Google’s recently released WebM format, but this will take some time for the browers and encoding software to catch up.

3. Fallback HTML requires multiple video files

The most common solution offered is to use nested HTML to allow browsers that don’t support <video> to fallback to flash. One of the best of these is called Video for Everybody and looks something like this:

<video>   <source src="myfile.mp4">   <source src="myfile.ogg">   <object src="flashplayer.swf?file=myfile.mp4">      <embed src="flashplayer.swf?file=myfile.mp4">   </object></video>

This works in all browsers, but it has a major problem: You must have two video files. If you attempt to use only MP4, Firefox on Opera will fail. If you remove the <source src=”myfile.ogg”>, Firefox and Opera will not fallback to the Flash <object>. They will just display a big, blank, black box with an X. The same goes if you only use OGG on browsers that don’t support OGG, or attempt to use WebM.

The HTML fallback mechanism only works if the browser doesn’t understand the <video> tag. It doesn’t work if it doesn’t understand the <source> file. So if you want to only use one file, then you must use JavaScript.

A Simple JavaScript Solution

Since I don’t want to maintain two versions of every video, I need a way to fallback to Flash for non-H.264 browsers. Here’s my simple solution using jQuery.

<video id="my-video">
   <source src="myfile.mp4" type="video/mp4">
</video>

<script>
(function() {
  var video = document.createElement("video");
  if ( typeof(video.canPlayType) == 'undefined' || // detect browsers with no <video> support
       video.canPlayType('video/mp4') == '') { // detect the ability to play H.264/MP4

       var video = $('#my-video');
       var videoUrl = video.find('source').attr('src');
       var flashUrl = '/flash/myplayer.swf';

       // create flash
       var flash = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ' +
				'	codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" ' +
				'	width="' + video.width() + '" height="' + video.height() + '" id="fallbackplayer">' +
				'		<param name="allowfullscreen" value="true" /> ' +
				'		<param name="movie" value="' + flashUrl + '?mediaUrl=' + videoUrl + '" /> ' +
				'		<embed id="dtsplayer" width="' + video.width() + '" height="' + video.height() + '" allowfullscreen="true" allowscriptaccess="always" ' +
				'			quality="high" name="fallbackplayer" ' +				'			src="' + flashUrl + '?mediaUrl=' + videoUrl + '" ' +
				'			type="application/x-shockwave-flash" /> ' +
				'</object>';

        // insert flash and remove video
        video.before(flash);
        video.detach();
  }
})();
</script>

The code is fairly simple. It just checks if the browser understands the <video> tag by checking for the “canPlayType” function, then it uses canPlayType to determine if the browser can play an H.264/MP4. If not, it inserts Flash as a fallback.

Please note: This is a simplified script for example purposes only. It needs flash version detection, and it should be turned into a jQuery extension, but it should still be a nice guide for

8 Responses to “Simple Cross-Browser HTML5 video with a single H.264 file and fallback options”

  1. Thanks for posting this. Am I right in assuming that with this script Firefox will default to the Flash player since you are no longer uploading the .ogg file? I have been uploading both for now. But I haven’t done any really large videos, so encoding and uploading to Ogg Theora hasn’t been a big deal.

  2. Weston Ruter says:

    So with WebM being the talk of the town, do you think you’ll be encoding videos in it as well as H.264?

  3. Mark Washeim says:

    hejo … I’ve got this running successfully with jquery 1.2(x) in a drupal cms with flac codec ogg files …. had to change the timeline.delegate to the old bind method and it works like a charm….

    Greetings and thanks for the great code.

    Mark

  4. danni says:

    Wow nice scripting… :) Is it possible to loop the mp4 in Flash/IE ? I tried to add "autoRestart=true" parameter in mediaelement.js but i cant get it to work :(

  5. Heff says:

    You obviously like the the interface (and some of the code) of VideoJS. Why not just build on that?

  6. Romi says:

    Hi john,
    thanks for mediaelements.js it´s great but have some troubles. Files are working from externals links but not from medias found. All mime times are there, same ff,sa,chr. Using WebDev or IIS7(mine registred).Other, could suggest you read this for Captions (http://www.brucelawson.co.uk/2010/jquery-accessible-html5-video-captioning-plugin/) you know that but you can extend your player to make like Dts. I lovelly more post john. Regards.

  7. Kashmir S. says:

    Hi

    It is not working for me with mozilla firefox. Could you please send me jquery script?
    with above script, it is showing black screen only.

  8. Leo says:

    Hi,

    Sorry, but despite your dayjob is webdesign and mine is not, I urge to please revisit the content of your post:

    - your code wont work without the unneeded javascript

    - you should use explain using multiple source tags as fallback

    - the fallback object should be inside the video object!

    - your SWF embed code is invalid, and valid it would work better (codebase, classid do not exist, just like Adobe’s made-up embed tag in the pre HTML5 erra does NOT exist. Having valid Flash embedding works better (I’ve seen hunderds of browsers now). It’s because browser vendors follow W3C and not Adobe.

    - the detach function does not remove the element, so likely to waste CPU, and in some cases to play content double (the 2nd player being invisible). You better use .remove()

    - video.canPlayType() never returns 0 or 1 (but “”, “maybe”, “probably”), so let the player remove the fallback a.s.a. it’s clear it’s not needed anymore. For example onplay=”$(‘#fallb’).remove()”

    I have not done much HTML5 but already server millions of videos, and started to use the video tag before vimeo and youtube did it on their sites.

    Please have a look at the player at http://unicycle.tv/en/play.php?v=1419-utvteamvideo2013 for a better example, and modify your post, as that would be of better help to others. Thanks for the effort!

Leave a Reply

Hi, I'm John Dyer. In my day job, I build websites and create online seminary software for a seminary in Dallas. I also like to release open source tools including a pretty popular HTML5 video player and build tools that help people find best bible commentaries and do bible study. And just for fun, I also wrote a book on the theology of technology and media.

Fork me on GitHub

Social Widgets powered by AB-WebLog.com.