Video Source by Screen Size

Published by Chris Coyier

Right after The Lodge opened up around here, I started getting reports right away about some videos not playing on the iPad. Ugh, crap, these are paying customers and they should be able to watch these things on a modern device.

I'm literally using HTML5 <video> to display the videos and hosting them on Amazon S3 (so they can be protected). I have been exporting them from Screenflow at as high of quality as I possibly could, giving me H.264 .mov files.

Apparently that's not great for iPad, it's better to be in .mp4 format. From a Mac, you an export from Quicktime (and thus Screenflow) as .mp4, but only in preset settings like "iPhone" or "iPad" or "Apple TV". That's fine I thought, I'll just choose "iPad". The quality was good and they continued to work on desktop WebKit browsers through HTML5 video.

For the record, I'm also doing:

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

from my root .htaccess file so that video gets served as the correct content type. Although I'm not sure exactly how much that helps since the videos are on S3.

In some quick testing, the videos played on the iPad too, yay!

But then reports kept rolling in of people trying to watch certain videos on the iPad and it failing. The exact behavior was the spinner just spinning and spinning and spinning. I'm actually using MediaElements.js here (there is no spinner on native UI's that I know of) but the root of playing the video is still just native HTML5 video (in supported browsers). I'm just using MediaElements.js as a nicer skin for the player.

I verified it. Some videos would play and some wouldn't. The only thing I could figure out was file size. I have one that was 75MB that would play and one that was 99MB that would not play. Strange but true.

So, I went back and re-exported all the videos I have posted so far in "iPod" .mp4 format, which is a bit smaller resolution thus smaller file sizes. But I didn't want to penalize everybody with lower quality video. What to do?

I just recently learned that you can use media attributes on the video element, like:

<video controls> 
   <source src="video-small.mp4" type="video/mp4" media="all and (max-width: 480px)"> 
   <source src="video-small.webm" type="video/webm" media="all and (max-width: 480px)"> 
   <source src="video.mp4" type="video/mp4"> 
   <source src="video.webm" type="video/webm"> 
</video>

(Really makes the <picture> element make sense, eh?)

This is awesome, and apparently supported by Chrome and Safari. But sadly, not the iPad (I tested it.) It's also at risk of being removed.

I needed something that is going to work right now, so I decided to just inject sources dynamically into the video. First I test the screen width to see if it's a fairly small screen (testing for 1200px here, the iPad reports 1024px). Using jQuery, and assuming I have some variables set with URL's to video sources:

var mainVideo = $('#the-video');

if ($(window).width() < 1200 && medQualVersion) {
  mainVideo.append("<source type='video/mp4' src='" + medQualVersionSrc + "' />");
} else {
  mainVideo.append("<source type='video/mp4' src='" + highQualVersionSrc + "' />");
}
mainVideo.append("<source type='video/webm' src='" + webMSrc + "' />");

// Wait until sources are appended to call MediaElements.js
mainVideo.mediaelementplayer();

I don't absolutely love this. For one, I wish the original high quality files would just work. For two, just because someone is on an iPad doesn't mean they want lower quality. They probably don't. But it's the only thing I could get to work right now.

I don't know if this is a ubiquitous problem for everyone or if it's something specific to all the various tech I'm using, but I thought I'd document it.