How I switched to displaying video consistently in all browsers using html5

HTML5 includes specifications for a video tag, that is meant to allow website developers to add a video to a page the same way they would add an image. This may seem unimportant, since you can already view video on a web page if you use plugins such as Flash Player, Quicktime, Silverlight, and RealPlayer. Yet the appearance of a dedicated tag is a big step forward for standardizing video playback across web browsers and devices. The future aim is that developers will only need to use one method for embedding a video, based on open standards—i.e. not controlled by one company—and it will work everywhere.

Crucially, this basic premise already works everywhere, because every browser can presently recognise the <video> tag (if necessary using a polyfiller such as Modernizr). The <video> element is designed to be usable without any detection scripts. You can specify multiple video files, and browsers that support HTML5 video will choose one based on what video formats they support. Browsers that don’t support HTML5 video will ignore the <video> element completely, but, as we will see below, you can use this to your advantage and tell them to play video through a third-party plugin instead.

The world of html5 video is changing fast, in exciting ways, that are perhaps best described by Mark Pilgrim in the video chapter of his excellent introduction to html5, Dive Into HTML5: if you'r unfamiliar with html5, I'd recommend reading through it before you start looking at implementing html5 video on your site.

In this post, we'll be looking at the different ways that you can use the html5 video tag to display your videos consistently and easily in all browsers using much more semantic markup.

Understanding html5 video structure: distinguishing between files, codecs and containers

Video file structure, which we'll be discussing in this blog post is a source of much confusion, so it might be useful clarifying some definitions first. It's worth remembering that what is referred as a 'video file', such as an mp4 file, for instance, is actually a container file, itself including (a) a video track, without audio, plus (b) one or more audio tracks (without video, but containing markers to synchronise audio and video). MPEG 4, Flash Video, Ogg and WebM (a more recent format) and the obsolescent Audio Video Interleave developed years ago by Microsoft are all examples of container formats.

When you actually play a video, you use a codec (a portmanteau Term to designate a coder combined with a decoder):

  • the most frequently used video codecs are H.264 (which is patent-encumbered), Theora (which is royalty-free and is most often seen in an Ogg container) and VP8 (which is royalty-free and modern, and was acquired by Google in 2010);

  • the main audio codecs are MP3 (which is also patent-encumbered and which Linux thus cannot play out-of-the-box), AAC (which Apple chose as the default format for the iTunes Store), and Vorbis (sometimes colloquially called 'Ogg Vorbis' and frequently included in Ogg containers).

The breakthrough brought about by html5 is that its <video> elment can be used to embed video on a page, without any restrictions as to which video codec, audio codec or container format you use. Crucially, the <video> element can link to multiple video files, and the browser, even if it's an an old one, will play the first video file it is capable of rendering [i].

Unfortunately, there is no combination of codecs and containers that will work in every browser and, since this is unlikely to change in the short-term, it means that although it is now possible, using html5, to play your videos across all browsers, in order to do this you'll have to encode your videos more than once and include all the required combinations of code in your page: so using html5 video effectively means, as we'll see below, providing the same video in at least two, or preferably three formats (ogg, mp4, and WebM) and adding code for a Flash fallback for older browsers.

For this reason, some users might be tempted, as I was initially, to resort to a hosted solution that simply provides them with an embed code that, unlike that provided by video hosting sites such as YouTube or DailyMotion, claims to work across browsers.

Vimeo Universal Player: uses iframes and doesn't work in all browsers

Until recently, I'd been hosting all my videos on Vimeo, which has designed what it calls a Universal Player giving you the ability to display your videos across browsers.

Except, it doesn't actually do that. Vimeo's Universal Player embad code doesn't work in certain situations (such as Firefox 3.6 without Flash enabled). It also causes validation errors, and Vimeo has basically acknowledged that it gives users a choice between serving valid code (but not being able to display our stuff consistently in IE) or break the page's W3C validation,.

I liked the idea of hosting the few videos I use on this site on a third-party site that didn't eat into my Amazon S3 bandwidth: so I installed the Vimeo Universal Player embed code on all my posts that had a video, only to find that there were loads of issues with this player and that quite a lot of my videos wouldn't play at all in certain situations.

Hosted solutions

As no hosted out-of-the-box solution exists that works, it makes sense to switch to using the html5 video tags and the cross-browser, semantic approach they provide, despite the need to re-encode your videos and rewrite your code that is the inevitable price to pay.

Vid.ly: just out of beta, uses iframes and still a bit buggy, but worth watching

In my search for another solution, I initially looked at yet another hosted solution, vid.ly. Vid.ly opened in private bet two months ago and initially tried using the new html5 <video> markup to embed videos, but this ran into numerous issues. Eventually, they went the same way as Video and reverted to iframes:

We experimented with <video> and with <script> tags but settled with the good 'ol <iframe> tag as it works consistently with the most browsers and devices.

The way vid.ly works is by uploading you existing video and processing it so as to provide all the possible formats you might need to display in any browser. Once the processing is complete, you're provided with an embed code that will do exactly that: display your video (which is now hosted by vid.ly) in any situation.

Although vid.ly does seem to have ironed out the bugs and sluggishness that affected its previous iteration, there didn't seem much point in switching to vid.ly just to get stuck with iframes again, so I looked elsewhere.

Sublime Video: a great hosted solution, but expensive

There's actually a bewilderingly long list of possible solutions to diplaying video across browsers using html5, the most impressive of which, unquestionably, is Sublime Video; the latter has just commercially launched, and now offers a reasonably wide range of plans as cheap as $99 per annum, makes it a rather expensive, but affordable alternative which dispenses you from having to host your content on Amazon S3. Unlike vid.ly and Vimeo's Universal Player, it uses valid html5 code, too.

Setting html5 video yourself with Video for Everybody

The basic setup: uses no javascript, works everywhere, but doesn't display consistently across browsers

If you balk at the Sublime Video price tag, it's perfectly possible to set up your site to use html5 video without it costing a penny, without relying on iframes or jevascript, using a set of clear-cut instructions designed by Kamen Design and known as Video for Everybody.

This takes advantage of the fact that html5 video degrades gracefully meaning that it can be set up to include fallbacks that will work in any browser that doesn't support html5 natively.

This code requires you to encode two video encodes in addition to the mp4 file which will serve as your base video: one Ogg file, and one MP4 file.

Louis Lazaris has pointed out that Video for Everybody's code structure is horribly complicated and suggested using PHP or CSS variables to avoid having to repeat the video url several times in one piece of code. I personally find it easier using TextExpander to include the link to my video on my Amazon Cloudfront bucket, from which it will be served to my users, and the dimensions of the player.

In order to encode the required versions of my videos, I used Miro Video Converter, an open source, GPL-licensed program for encoding video in multiple formats.

You'll need to convert your video to (1) WebM, (2) Theora and (3) iPhone format, and upload them somewhere you can serve them from: I use a folder in my Amazon Cloudfront bucket. You'll then be able to assemble them into a single <video> element that works across browsers.

You can actually get away with using just Ogg (Theora) and MP4 (iPhone). Caden Design explains why:

On January 11th 2011, Google announced that it would be removing H.264 support from Chrome. It is clear that Google’s long-term solution is to transition YouTube to HTML5/WebM. With the release of Firefox 4, a large percentage of browsers will support WebM, and others through the use of installed codecs (Safari and IE9). Only iOS is completely without WebM support at this time.

Please note that you do not have to include WebM video in your HTML5 video tags as both Chrome and Firefox still support Ogg. WebM will provide you higher quality, and likely wider compatibility in the very near future, but right now it is completely an optional extra.

You don't, on the other hand, need separate Flash encoding: the MP4 file is supported by Flash so it serves a dual purpose.

You will, however, need to ensure that your server is using the correct mime-types. My least-favourite non-IE browser, Firefox, will not play the Ogg video if the mime-type is wrong. Place these lines in your .htaccess file to send the correct mime-types to browsers:

AddType video/ogg  .ogv
AddType video/mp4  .mp4
AddType video/webm .webm

If you want to fine-tune the quality of your videos, which is something that isn't important to me as I use videos only for illustrative purposes, Mark Pilgrim gives very detailed advaice on using Firefogg, ffmpeg2theora and Handbrake for this purpose.

My excellent friend Brett Terpstra has devised a clever method using ffmpeg and ffmpeg2theora and a shell script and Hazel.app to automatically generate multiple versions of a video for use with the HTML5 video tag.

The following code (using mp4 and ogg, but you could add WebM as an additional fallback) will play your video consistently across all browsers, without the need to resort to javascript:

<video width="640" height="360" controls>
    <source src="__VIDEO__.MP4"  type="video/mp4" />
    <source src="__VIDEO__.OGV"  type="video/ogg" />
    <object width="640" height="360" type="application/x-shockwave-flash" data="__FLASH__.SWF">
        <param name="movie" value="__FLASH__.SWF" />
        <param name="flashvars" value="controlbar=over&amp;image=__POSTER__.JPG&amp;file=__VIDEO__.MP4" />
        <img src="__VIDEO__.JPG" width="640" height="360" alt="__TITLE__"
             title="No video playback capabilities, please download the video below" />
    </object>
</video>
<p>   <strong>Download Video:</strong>
    Closed Format:  <a href="__VIDEO__.MP4">"MP4"</a>
    Open Format:    <a href="__VIDEO__.OGV">"Ogg"</a>
</p>

Javascript-based projects that improve on Video for Everybody

So you can play all your videos in any browser using the Video for Evrybody html code. On the other hand, this will display slightly differently in different browsers, depending on those browsers' original settings for video. If, like me, you want display consistency you need a javascript solution: luckily several packages exist designed to add this precise feature on top of the existing html5 code described above.

MediaElement.js uses a custom Flash or Silverlight player that mimics the native HTML5 API so that interacting with the video from JavaScript is the same regardless of browser. It's beautifully coded but a bit top-heavy for what I need: Instead of offering an HTML5 player to modern browsers and a totally separate Flash player to older browsers, MediaElement.js upgrades them with custom Flash and Silverlight plugins that mimic its own superb API.

Video.js is an equally elegant, but more lightweight package that I've chose to implement on this site. A number of skins have been written for it that make it display consistently and easily across all browsers, using the following code:

<!-- Begin VideoJS -->
  <div class="video-js-box">
    <!-- Using the Video for Everybody Embed Code http://camendesign.com/code/video_for_everybody -->
    <video class="video-js" width="640" height="264" controls preload poster="http://video-js.zencoder.com/oceans-clip.png">
      <source src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
      <source src="http://video-js.zencoder.com/oceans-clip.webm" type='video/webm; codecs="vp8, vorbis"' />
      <source src="http://video-js.zencoder.com/oceans-clip.ogv" type='video/ogg; codecs="theora, vorbis"' />
      <!-- Flash Fallback. Use any flash video player here. Make sure to keep the vjs-flash-fallback class. -->
      <object class="vjs-flash-fallback" width="640" height="264" type="application/x-shockwave-flash"
        data="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf">
        <param name="movie" value="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" />
        <param name="allowfullscreen" value="true" />
        <param name="flashvars" value='config={"playlist":["http://video-js.zencoder.com/oceans-clip.png", {"url": "http://video-js.zencoder.com/oceans-clip.mp4","autoPlay":false,"autoBuffering":true}]}' />
        <!-- Image Fallback. Typically the same as the poster image. -->
        <img src="http://video-js.zencoder.com/oceans-clip.png" width="640" height="264" alt="Poster Image"
          title="No video playback capabilities." />
      </object>
    </video>
    <!-- Download links provided for devices that can't play video in the browser. -->
    <p class="vjs-no-video"><strong>Download Video:</strong>
      <a href="http://video-js.zencoder.com/oceans-clip.mp4">MP4</a>,
      <a href="http://video-js.zencoder.com/oceans-clip.webm">WebM</a>,
      <a href="http://video-js.zencoder.com/oceans-clip.ogv">Ogg</a><br>
      <!-- Support VideoJS by keeping this link. -->
      <a href="http://videojs.com">HTML5 Video Player</a> by VideoJS
    </p>
  </div>
  <!-- End VideoJS -->

There are also WordPress plugins: External Video for Everybody and WordPress HTML5 Video Player (the latter based on Video.js). I can't see any point in using these myself, and haven't tried them, but if you like using plugins, you may want to consider them.

The end result: an example of a video displayed in a post on this blog, using Video for Everybody code, made consistent across browsers using the Video.js solution.

I've personally found that a combination of Video for Everybody code and the video.js javascript will display my videos, which are hosted on Amazon S3, consistently on any browser. Depending on your particular setup, however, any of the other solutions described above could also work for you, allowing to make full use of the new video capability offered by html5.

_______________
  1. At present, browser video support can be summarised in the following list, given by Mark Pilgrim: (1) Mozilla Firefox (3.5 and later) supports Theora video and Vorbis audio in an Ogg container. Firefox 4 also supports WebM; (2) Opera (10.5 and later) supports Theora video and Vorbis audio in an Ogg container. Opera 10.60 also supports WebM; (3) Google Chrome (3.0 and later) supports Theora video and Vorbis audio in an Ogg container. Google Chrome 6.0 also supports WebM; (4) Safari on Macs and Windows PCs (3.0 and later) will support anything that QuickTime supports. In theory, you could require your users to install third-party QuickTime plugins. In practice, few users are going to do that. So you’re left with the formats that QuickTime supports “out of the box.” This is a long list, but it does not include WebM, Theora, Vorbis, or the Ogg container. However, QuickTime does ship with support for H.264 video (main profile) and AAC audio in an MP4 container; (5) Mobile phones like Apple’s iPhone and Google Android phones support H.264 video (baseline profile) and AAC audio (“low complexity” profile) in an MP4 container; (6) Adobe Flash (9.0.60.184 and later) supports H.264 video (all profiles) and AAC audio (all profiles) in an MP4 container; (7) Internet Explorer 9 supports all profiles of H.264 video and either AAC or MP3 audio in an MP4 container. It will also play WebM video if you install a third-party codec, which is not installed by default on any version of Windows. IE9 does not support other third-party codecs (unlike Safari, which will play anything QuickTime can play); (8) Internet Explorer 8 has no HTML5 video support at all, but virtually all Internet Explorer users will have the Adobe Flash plugin. []