Make sites serve you HTML5 video in Safari

John Gruber of Daring Fireball has a cool post on tricking websites to display HTML5 video when they say they can only play Flash. Many sites will tell you they require Flash, even when they actually support HTML5 video for iOS devices.

To add to Gruber’s post, there’s two reasons a site might do this:

  1. They’re trying to protect their content from being easily downloaded, which HTML5 video can’t do very well yet.
  2. They assume everyone with a browser has Flash, and just serve HTML5 video to iOS devices.

So for this first, this is actually a hack to download content some publishers might not want you to. I probably shouldn’t be publishing this since security of the content is one of the main reasons HTML5 video will still take time to spread. But for that purpose, it’s really not hard to figure out.

For the second, it’s kind of lazy implementation of fallbacks. It’s pretty easy to check if Flash is supported, and if not, fall back to HTML5, instead of checking for a specific user agent string. So for sites using VideoJS, this method wouldn’t work, but there also wouldn’t be a need because VideoJS would fallback appropriately to HTML5.

Gruber has disabled Flash in Safari for better performance with video. That says a lot. Most people probably won’t go to same effort he has, but I know he’s not the only one.

1.1.5 Release - Subtitles using track, Android fix & more

  • Feature: Switched to track method for setting subtitles. Now works like spec.
  • Feature: Created “players” concept for defining fallbacks and fallback order
  • Fix: Android playback bug.
  • Fix: Massive reorganization of code to make easier to navigate

I’ve switched the subtitles to use the new track element defined in the HTML5 spec. You can now add subtitles by creating a track element pointing to your WebSRTsubtitles source.

<video ...>
  <track kind="subtitles" src="../" srclang="en-US" label="English"></track>

The closing track tag is needed, otherwise Safari thinks everything else is a child of the track, even with a self-closing track tag. Not sure why that is, but it’s kind of annoying.

Also a fix for Android playback was added. Android HTML5 video is pretty rough. The canPlayType function returns nothing on Android so VideoJS has a check to see if the source is mp4/m4v, and assumes it’ll play. Then VideoJS adds a click event to the video so it’ll play when you touch it. Also the Android will show the poster image, but no indication that it’s a video and not just an image. Hopefully this will be improved in the next Android version.

Beyond that, I did a massive reorganization of the code, so it should be easier to navigate if you’re planning to hack at it or contribute.

Download version 1.1.5

Version 1.1.4 Release - CSS Loading Spinner & More

The most notable update in this version is a loading indicator (spinner), for when the video is buffering or seeking. The spinner works pretty well, however it’s limited by how accurately each browser tells us what it’s currently doing through triggered events. The spinner works best in Firefox so far. Safari/Chrome are less consistent with what events are triggered and when. For this reason I’m using a more careful approach that makes sure the spinner gets hidden, as opposed to making sure the spinner always shows when the player is busy. There’s a few bugs I had to account for too, like when Safari throws a “waiting” event, but then no other event to let us know it’s not waiting anymore.

The spinner icon is made with CSS3 effects (border-radius and transform). The spinning animation is created with a little javascript for now. In webkit browsers the animation could have been done with CSS3 animation, but I’d rather keep it consistent between browsers. The technique comes from Kilian Valkhof with initial integration into VideoJS by Janez Troha (dz0ny)

Other features and fixes include:

  • Feature: Added loading spinner.
  • Feature: Improved styles loaded checking.
  • Feature: Added volume() function to get and set volume through the player. - Fix: Fix issue where FF would loop video in background when ended.
  • Fix: Bug in Chrome that shows poster & plays audio if you set currentTime too quickly.
  • Fix: Bug in Safari where waiting is triggered and shows spinner when not needed
  • Fix: Updated to show links if only unplayable sources and no Flash.
  • Fix: Issue where if play button was loaded after play, it wouldn’t hide.

Download version 1.1.4

Version 1.1.3 Release

Version 1.1.3 of VideoJS is now available.

Probably the most notable change is a switch to using a big play button before the movie plays for the first time, as opposed to showing the control bar. The main reason for doing this is actually a bug in Safari. If you try to call any functions on the video other than play, before the video has loaded, Safari will error out. Some people mentioned that fullscreen mode did not work in Safari for them, and this is most likely what was happening for them. This would only happen if you were not preloading the video. You can still go back to showing the controls first through the showControlsAtStart option, but it’s not recommended.

Other features and fixes include:

  • Feature: Width/Height functions for resizing the player
  • Feature: Made initial click & hold trigger new value on progress and volume
  • Feature: Made controls not hide when hovering over them
  • Fix: Removed trailing comma that was breaking IE7
  • Fix: Removed some vars from global scope
  • Fix: Changed a document.onmousemove to an eventListener to prevent conflicts
  • Fix: Added a unique ID to FlowPlayer demo object to fix a FlowPlayer bug. Thanks @emirpprime.
  • Fix: Safari error on unloaded video

Let me know if you have any questions.

iPad & iPhone Video Poster Fix (bonus Javascript Placement Fix)

Bug #1 - Poster Attribute

If you include the poster attribute on the video tag when you’re using <source> tags, the video won’t work on iPads & iPhones using iOS 3. You’ll see a broken play button, or no play button at all. On the iPad specifically, playback in inconsistent. Sometimes it’ll work and sometimes it won’t. This is documented on the Video for Everybody site.

Bug #2 - Javascript in the Head

This is a fun one… If you include Javascript in the head of your page, it’ll break playback on the iPad (also inconsistent). If you move the Javascript to the bottom of the page, and still include a stylesheet, the iPad will work, but the iPhone 3 won’t. I first read about this in a post on the blog, and then ran into it myself when redesigning the VideoJS site. Their original solution was to put the JS at the bottom of the page for iPads only (fun).

Apple’s iOS4 seems to fix both of these problems on the iPhone, but until iOS4 is available on the iPad, and everyone in the world upgrades their devices, we have to deal with this.

Fix for iOS 3

The problem seems to be some kind of race condition, that trips up the devices. The solution that has fixed both of these for me is to add the playable source directly to the video tag, and tell the video to load (all through Javascript).

I’ve added all this to VideoJS 1.1.2, but here’s the basics of how it works.

var video = document.getElementById("your_video");
    var children = video.children;
    for (var i=0,j=children.length; i<j; i++) {
      if (children[i].tagName.toUpperCase() == "SOURCE") {
        var canPlay = video.canPlayType(children[i].type);
        if(canPlay == "probably" || canPlay == "maybe") {
          video.src = children[i].src;
          break; // or return or whatever

So loop through the source elements, find the one that’s compatible, and add that source to the video src. Then trigger the video’s load() function.

That seems to fix both issues. This will not make the poster show up in either device.It just makes makes the video playable. Sometimes you’ll see it flash the controls and then go back to the big play button.

Any feedback is appreciated.

Let’s go Apple, get iOS4 out to everybody!

New VideoJS Site (Now with more HTML5)!

I told myself when the site reached 100,000 visits I would redesign it. Well that number’s come and gone, so here it is.

I also took this as an opportunity to code an HTML5 based site, using tags like header, footer, and section. And I built it on the newly popular HTML5 Boilerplate. Actually I built a WordPress them for HTML5 Boilerplatefirst, in case you’re interested in doing the same.

I got to use some fun CSS tricks throughout as well. One of them is the thin color bar at the top of the page. Resize the window and watch it go!

I also added this blog and a twitter account, where I’ll be posting updates to VideoJS, as well as general HTML5 video news.