UPDATE: With the recent release of JW6.9 (30th June 2014) the JW Team have fully integrated the YouTube iFrame API into the player. As a result jwTube should not be used with JW6.9+ as the two don’t play well together!

With the recent update of Apple’s iOS to version 7, JW Player implementations that use YouTube as a media format have started to experience issues.

YouTube issue in JW Player on iOS7

The main problem is that YouTube videos appear to halve in height – even though the JW Player container remains the correct height.

The JW Player team have acknowledged this to be an issue, and have stated that it will be addressed in JW 6.8 – which is not likely to be available until early 2014.

UPDATE: This has now been resolved in JW6.8 (released 6th Feb 2014), however JW playlists and event hookup in HTML5 mode are still missing.

 

In order to fill the void between now and then, I have developed a “patch” to resolve this issue.

Whilst I was at it, I also decided to address a few other JW Player 6 + YouTube + HTML5 mode annoyances, such as:

  • Allowing playlists on iOS
  • Allowing merged/mixed playlists
  • Controlling YouTube volume using the JW Player control bar
  • Exposing YouTube events to JW Player
  • Support for modern Android devices (since v1.4)

Using jwTube

The basic implementation is very simple:

1) Download the jwTube patch.

You can get the jwTube patch here.

2) Load the patch after JW player

Include a link to the jwTube patch in your page <HEAD> after the jwplayer.js library, for example:

<!-- JW Player Library -->
<script src="[/path/to/jwplayer]/jwplayer.js"></script>
<!-- jwTube patch -->
<script src="[/path/to/jwtube]/jwtube.min.js"></script>

3) Enable jwTube

If you are using jwTube version 1.4 or greater, then that’s it – there is no longer any additional configuration required. jwTube will make use of your existing configuration parameters to build mixed/merged playlists, and will automatically select the relevant mode for your device/platform.

Examples of using jwTube v1.4 can be found here.

NOTE: Dynamically added JW Players still require a call to jwtube.patch(player) immediately after the .setup({...}) call, passing the resulting JW instance as the player parameter.

 

If you are using versions earlier than v1.4 then some additional configuration is required in order to apply the jwTube patch:

  • Use the "file": syntax to reference your media – whether they are individual YouTube videos or a playlist
  • Include "type":jwtube.setType() as part of the main setup configuration (for single files) or for the first playlist item in an inline playlist – at the same level as the "file" parameter.
    • If you’d prefer JW Player to only be put into HTML5 mode when on iOS7 – giving a better default experience for PC users – use this setting instead: "type":(jwtube.iOSVersion()>=7?jwtube.setType():"youtube")
  • Do not include the "primary" parameter as part of the main setup configuration
  • For dynamically added JW Players, call jwtube.patch(player) immediately after the .setup({...}) call, passing the resulting JW instance as the player parameter

More specific examples of using earlier versions can be found here.

Hooking up events

Once the JW Player has been patched, you can hook into the YouTube “play”, “pause” and “buffer” events using the following approach:


<script type="text/javascript">
  jwplayer("container").setup({
    "title":"Danny Macaskill - Industrial Revolutions",
    "description":"Industrial Revolutions is the amazing new film from street trials riding star Danny Macaskill. Filmed and edited for Channel 4's documentary Concrete Circus by Stu Thomson from http://www.CutMedia.com",
    "image":"danny_macaskill.jpg",
    "width": "50%",
    "aspectratio":"16:9",
    "file": "http://www.youtube.com/watch?v=ShbC5yVqOdI",
    "type":jwtube.setType()
  });
  // Due to a bug in JW6.7, we have to re-get the player instance
  var jwp = jwplayer("container");
  jwp.ytOnPlay = function(player){
     // YouTube video is playing
  };

  jwp.ytOnPause = function(player){
     // YouTube video is paused
  };

  jwp.ytOnBuffer = function(player){
     // YouTube video is buffering
  };
</script>

jwTube for WordPress

In order to get jwTube working with the JW Player WordPress Plugin, I’ve had to create an alternative patch file.

This needs to be loaded into the HTML Head of your WordPress template.

You can get the jwTube for WordPress patch here.

Additionally, you need to include the following tag as part of the JW Plugin shortcode:

jwtube="powered-by-haiku.co.uk"

for example

jwplayer mediaid="xxx" jwtube="powered-by-haiku.co.uk"

results in the following:

[jwplayer mediaid=”602″ jwtube=”powered-by-haiku.co.uk” controlbar=”true” test=”jh”]

NOTE: I have restricted this to only modify the JW Plugin behavior on iOS7.

For those of you who use JW Player with playlists, but are frustrated that a bug in JW6 has broken single finger scrolling on touch devices – I hope you consider this a workable solution.

Jeroen from LongTail Video has indicated that they will be including single-finger scrolling in JW Player 6.5, which by all accounts is slated for June 2013, but in the meantime he suggests you stay with JW 5.10.

Update
JW Player 6.5 was released mid-June 2013 – and it still has no support for single finger scrolling of playlists on touch devices.

Maybe JW 6.6 will finally have it – which is due end-July/early August…

Update: September 2013
JW Player 6.6 does now support single finger scrolling of playlists on touch devices… however, the implementation is a bit strange.
It’s not a smooth scrolling effect. The playlist seems to scroll the height of the playlist viewport for each finger swipe… Which is fine on small playlists, but a nightmare on larger ones. Oh dear!

 

Whilst I’ve written an HTML Configuration library for JW Player, which includes a fix for single-finger scrolling, I appreciate that this could be considered too much of a deviation from the JavaScript only embed method many people use.

With this in mind, I’ve extracted the “iScroll bit” into a discreet library which provides single-finger scrolling to JS embedders with a minimum of fuss!

How to use

1) Download the touchScroll library.

You can get the touchScroll library here.

2) Load the library after JW player

Include a link to the touchScroll library in your page <HEAD> after the jwplayer.js library, for example:

<!-- JW Player Library -->
<script src="[/path/to/jwplayer]/jwplayer.js"></script>
<!-- touchScroll Library -->
<script src="[/path/to/touch-scroll]/jw6-touchscroll.min.js"></script>

Apply touchScroll to your players

In order to apply the touchScroll feature, you need to make a call to jwplayer.touchScroll(), passing the current player as a variable, but only once the playlist is ready.

This is achieved by attaching an event callback to your JW Player as follows:

var my_player = jwplayer("my_id").setup({...});
my_player.onPlaylist(function(){ jwplayer.touchScroll(this); });

The touchScroll() function takes an optional second argument which is the time to wait (in milliseconds) before trying to hook up touchScroll. This shouldn’t be necessary in the majority of cases, but depending on the number of other events attached to the player you may need to introduce a delay. Half a second delay (500) seems to work in the worst case scenarios.

JW HTML Config is a standalone JavaScript library which, once loaded on your page, allows you to setup and configure JW Player videos and playlists without the need for JavaScript knowledge.

JW HTML Config uses a simple structure of HTML tags in association with data- attributes to configure both JW5 and JW6 versions seamlessly.

In addition to providing this unified approach to configuring JW Player, the JW HTML Config library includes the following features:

  • Makes JW Player act responsively within the body of the page or viewport of a mobile device whilst maintaining the correct aspect ratio
  • Resolves common setup and playback issues associated with “Phantom videos” when embedding over the native video tag
  • Resolves video/poster sizing issues in JW5 on IE9+ in HTML5 mode
  • Allows you to add YouTube videos to JW6 inline playlists and have them play in HTML5 mode (including on iOS) – this original JW5 functionality has been removed from JW6
  • Caters for the playlist listbar in JW6 to be positioned to the left or top of the video (HTML5 mode only) – original JW5 functionality which has been removed from JW6

Setup

I’ve tried to keep the setup and configuration as simple as possible. However, if you run into any issues feel free to ping me message on twitter (@jherrieven) and I’ll be happy to help.
Please bear in mind this is a work in progress and as such may not currently cater for the more complex JW Player configurations.

DOCTYPE

At the top of your page make sure the HTML5 doctype is declared:

<!DOCTYPE html>

HTML5 video will not work smoothly in some browsers (IE9 for example) if this declaration is missing.

Include the libraries in the <HEAD>

Include a link to the JW Player and JW HTML Config libraries in the head section of your page:

<!-- JW Player Library -->
<script src="[/path/to/jwplayer]/jwplayer.js"></script>
<!-- JW HTML Config Library -->
<script src="[/path/to/jw-html-config]/jwplayer-html-config.min.js"></script>

Whilst it is recommended to have the JW Player library load in the head section of your page, this may not always be possible – this can therefore be loaded within the body tag.

If including the JW HTML Config library in the body tag also, this should appear after the JW Player library at the bottom of the body tag.

That’s it! You are now ready to use HTML to configure JW Player to ensure consistent playback of your videos.

HTML Configuration

Getting started

For each video you wish to configure with JW Player you simply need to wrap the native video tag in a new settings div as follows:

<div class="jw-settings" id="my_simple_settings">
     <video id="my_simple_video" poster="/posters/big-buck-bunny-preview.jpg" preload="none">
          <source src="/videos/mp4/big-buck-bunny.mp4" type="video/mp4" />
          <source src="/videos/webm/big-buck-bunny.webm" type="video/webm" />
     </video>
</div>

It is important to note that both the div.jw-settings and video tags have a unique id attribute.

Adding the above code to your page results in the following, responsive, JW Player video being displayed:

Setting up Flash fall-back

Ahem… That is of course unless you are using IE8 or less (due to it not recognising the native video tag) or Firefox (due to my server sending the wrong MIME-TYPE of text/plain for the webm video).
Incidentally, Opera uses the webm version too but isn’t as fussy about the MIME-TYPE being correct.

For academic purposes I’ve deciding to leave the MIME-TYPE as it is, and instead make use of JW Player’s fallback to Flash functionality. Doing this should then enable both IE8 and Firefox to play the mp4 version using the JW Flash player instead.

This is achieved by simply adding a div.jw-modes configuration block inside the div.jw-settings block, as follows:

<div class="jw-settings" id="my_simple_settings_2">
     <video id="my_simple_video_2" poster="/posters/big-buck-bunny-preview.jpg" preload="none">
          <source src="/videos/mp4/big-buck-bunny.mp4" type="video/mp4" />
     </video>
     <div class="jw-modes">
          <div class="jw-mode" data-type="html5"></div>
          <div class="jw-mode" data-type="flash" data-src="/jwplayer/v5/player.swf"></div>
     </div>
</div>

The inclusion (and order) of each div.jw-mode setting tells JW Player to try and render using the html5 mode first, and failing this fall-back to flash. The flash mode setting also includes a data-src attribute to indicate where the JW Flash Player is located.

NOTE: I removed the webm source from the video tag as Firefox would assume it can play this using the html5 mode, and therefore not actually fall-back to Flash.

Providing a non-Flash fall-back

This will now display JW Player in html5 mode if your browser supports mp4 video playback, and will fall-back to use the JW Flash player if not. But what happens in the scenario where the browser doesn’t support the video type natively and it also doesn’t have the Flash plugin installed?

This is where ideally we would provide a further level of fallback in the form of video download links.

This is easily done by including a div.videoFallback block within the video tag. This block will only be displayed given the scenario that none of the video source types are supported natively (or via Flash) and the Flash plugin is not installed.

<div class="jw-settings" id="my_simple_settings_3">
     <video id="my_simple_video_3" poster="/posters/big-buck-bunny-preview.jpg" preload="none">
          <source src="/videos/mp4/big-buck-bunny.mp4" type="video/mp4" />
          <div class="videoFallback">
               <strong>Download video</strong>
               <p>Please note that in order to view this video you either need a web browser that supports HTML5 video or to ensure both JavaScript and Flash are enabled for your browser.
Alternatively you can use the link below to view the video in your player of choice</p>
               <a href="/videos/mp4/big-buck-bunny.mp4">MP4 version</a>
          </div>
     </video>
     <div class="jw-modes">
          <div class="jw-mode" data-type="html5"></div>
          <div class="jw-mode" data-type="flash" data-src="/jwplayer/v5/player.swf"></div>
     </div>
</div>

Whilst the fallback HTML should consist of a div with the class set to videoFallback, the contents of this div can be customised to suit your needs.

Using the download fall-back instead of the video tag

One final configuration approach I want to explore in this Getting started section is the concept of using the fallback block and download links as the actual source settings for JW Player setup – eliminating the use of a video tag.

Whilst this would mean there is no longer the potential to play a video in the native browser player – in the case where JavaScript is disabled – it does provide a more consistent experience for users across all devices, reduces potential page load time, eliminates buffering clashes and overcomes any restrictions on CMS’s allowing users to include video tags inline.

This basically involves replacing the video tag with a div.jw-video settings block which contains replacements for the source tags in the form of a.jw-source links. This can be seen in action below:

<div class="jw-settings" id="my_simple_settings_3">
     <div class="jw-video" id="my_simple_video_3" data-poster="/posters/big-buck-bunny-preview.jpg">
          <strong>Download video</strong>
          <p>Please note that in order to view this video you need to ensure JavaScript (and possibly Flash) is enabled for your browser.
Alternatively you can use the link below to download and view the video in your player of choice</p>
          <a class="jw-source" href="/videos/mp4/big-buck-bunny.mp4" data-type="video/mp4">MP4 version</a>
     </div>
     <div class="jw-modes">
          <div class="jw-mode" data-type="html5"></div>
          <div class="jw-mode" data-type="flash" data-src="/jwplayer/v5/player.swf"></div>
     </div>
</div>

Results in the following output:

Download video

Please note that in order to view this video you need to ensure JavaScript (and possibly Flash) is enabled for your browser.

Alternatively you can use the links below to download and view the video in your player of choice.

MP4 version

As the web’s most popular video player, the use of JW Player in content management systems is as deep as the web is wide.

To date, most of these implementations are based on JW Player version 5 and therefore have JW5 and media specific embedding techniques: using the OBJECT, EMBED or VIDEO tag.

With the recent release of the latest version of JW Player (JW6) you naturally expect a few issues to surface when it comes to upgrading, however, you’d also expect a bit of direction from the makers of the product in order to ensure this process is as painless as possible – especially when you consider:

  • Some sites have been embedding JW5 videos for years – and they have hundreds of videos embedded using “legacy” techniques
  • LongTail Video in their wisdom have removed all but the JavaScript method for embedding – and even this they have changed quite substantially
  • Official support for JW5 is likely to disappear within the next 18 months

Unfortunately it would appear that with all the changes happening within the Longtail/JW camp and their desire to get JW6 rolled out, they have taken their eye off the ball, and in doing so appear to have shown a complete lack of consideration towards their established user-base.

To expect users to re-visit the embed code of every previous video hosted on their template driven site, just so they can upgrade to the more expensive and less functional version of JW Player is hugely narrow-minded.


Following on from a post I saw in the JW Player support forums relating to this issue, I decided to have a crack at developing a low impact solution to having JW5 and JW6 co-exist across an established site.

This is an example of how to get JW Player working with:

  • JW5 for pages with a legacy VIDEO, OBJECT or EMBED setup
  • JW6 for pages with the new JS only embed approach
  • Whilst maintaining a single HTML Head template – used by BOTH sets of pages.

NOTE: It requires modifying the “jwplayer.js” file that is used by the existing JW5 embed methods.

Although this may sound undesirable, there is a low risk of this file changing through official channels in the future.


Let’s do this!

Step 1

  • Open the “jwplayer.js” file provided as part of the JW5 install in notepad
  • Find and replace all instances of “jwplayer” with “jwplayer5
  • Find and replace all instances of “$jw” with “$jw5
  • Save and rename the file to “jwplayer5.js” in it’s original directory

Step 2

Update the HEAD of your HTML Page Template to include the following (this assumes JW6 is available to be linked to either on your server or from a CDN):


<script type="text/javascript" src="[/original/path/to/jw5]/jwplayer5.js"></script>

<script type="text/javascript" src="[/new/path/to/jw6]/jwplayer.js"></script>

Step 3

Include the following additional script in the HEAD after the two jwplayer library references:


<script>
(function(){
var xmlHTTP;
var sURL = self.document.location.href;
if (window.XMLHttpRequest){ xmlHTTP=new XMLHttpRequest(); } else {xmlHTTP=new ActiveXObject("Microsoft.XMLHTTP");}
try{
xmlHTTP.open("GET",sURL,false);
xmlHTTP.onreadystatechange=function(){
if(xmlHTTP.readyState!=4){ return; }
if (xmlHTTP.status==200){
var sRet = xmlHTTP.responseText.toLowerCase();
// ** Modify this line to include specific conditions to switch to JW5 **
if(sRet.indexOf('<'+ 'video ') > -1 || sRet.indexOf('<'+ 'embed ') > -1 || sRet.indexOf('<'+ 'object ') > -1){
jwplayer = null;jwplayer = jwplayer5;$jw = null;$jw = $jw5;
} else {
jwplayer5 = null; $jw5 = null;
}
if(top.console) console.info(jwplayer.version);
} else {
alert('Are you using this locally? It doesn't work unless on a server!');

}
};
xmlHTTP.send(null);
} catch (e) {
// TODO: handle exception
}
})();
</script>

That’s it!

Modify the line indicated in the above script, as required, to determine what it is you wish to use as a trigger to switch to JW5.


The following two pages demonstrate the dynamic switching between JW versions:

With VIDEO tag (loads JW5) | Without VIDEO tag (loads JW6)

JW Player and HTML5 Video

When it comes to embedded media on the web, the JW Player from LongTail Video is widely regarded as one of the best solutions in terms of producing consistent results across a wide range of browsers and devices.

Since release 5.3, JW Player has included a specific embedding method that caters for the creation of a video player with seamless failover between Flash and HTML5 modes (and vice versa). It also introduced the ability to use the parameters defined in HTML5 video and source tag attributes as the default configuration options for setting up the player. This means that once the JW Player JavaScript library has been loaded in the page, a JW Player instance can be generated using a simple video tag and zero extra JavaScript – an excellent enhancement to ensure the widest availability of video regardless of a user’s individual browser configuration.

JW HTML CONFIG

In my role as Web Developer for a large UK organisation, I recently tasked myself with writing an extension to the JW Player solution with the primary aim of simplifying the configuration process (particularly in relation to playlists) whilst additionally producing an output that reacts responsively. The aim was to provide a solution which doesn’t require additional, separate JavaScript configuration – all settings are to be driven from simple inline HTML.

In much the same way the JW Embedder uses the principle of progressive enhancement by interrogating the HTML5 video tag and attributes and then dynamically producing a configuration object, which is used as the basis for the player setup, the solution makes use of additional structured settings blocks (tags with data- attributes) to extend this concept further.

During the development of this extension (which takes the form of a small JavaScript library, and details can be found here) I encountered a number of “setup and playback inconsistencies” which, when checking in the JW Player forums, became clear I was not alone in experiencing. These “unexplained hiccups” appear to be increasingly common and a worrying source of frustration for users who are implementing (or more likely updating) JW Player to make use of the more elegant and accessible HTML5 first approach.

UNEXPLAINED HICCUPS

To understand more about how these frustrations manifest themselves – let’s explore a likely route to JW Player/HTML5 implementation :

Ok. Let’s say for arguments sake I have some experience in implementing JW Player, going back to before 5.3, when I happily managed to get MP4 videos playing on my website using the Flash embed method. Life is sweet! A single video format played through a 3rd party plugin. If you don’t have the plugin, you don’t get the video – that’s just the way it is I’m afraid!

[Time passes by]

Now I’ve been thinking, maybe my website should make more of an effort to cater for a wider audience and start supporting HTML5 video – specifically to serve those Flash intolerant devices! No problem. As I understand it these devices support MP4 video natively, so all I need to do is upgrade to the latest version of JW Player (let’s say 5.7) and let it handle the Flash to HTML5 failover as required. Perfect.

Erm… or maybe not! It seems that my MP4 video files don’t actually play on the latest iDevices. After a mild panic, and a little bit of research, I am able to figure out that while it seems Flash is quite forgiving about the encoding of video, the iDevice is not. Resolving the problem involves re-encoding the videos specifically for the iDevice, which although a bit of a headache, is perfectly manageable and the result is worth it.

[More time passes]

As my understanding of my website audience evolves further, and my desire to reach as many different users – on a broad range of devices – becomes a key objective, I decide to switch my video strategy to serve HTML5 first with a Flash fall-back.

After a bit of research, I decide that the best approach (involving the least effort) involves simply switching my JW Embed method to make use of the native video and source tags and providing a WebM version of the video – to cater for native playback in Firefox & Opera. I also update JW Player to version 5.10 and specifically include the modes block in my setup object – telling it to use html5 mode first. This is as described in the JW Player documentation:

<script src="/jwplayer/jwplayer.js" type="text/javascript"></script>
<video height="270" width="480" id="myVideo">
<source src="/static/bunny.mp4" type="video/mp4">
<source src="/static/bunny.webm" type="video/webm">
</video>
<script type="text/javascript">
// <![CDATA[
jwplayer("myVideo").setup(
{ modes:
[
{ type: 'html5' },
{ type: 'flash', src: '/jwplayer/player.swf' }
]
});
// ]]>
</script>

One change I make to this code is to place the script tags at the bottom of the body – as this is commonly best practice right?! My code now looks like this:

<html>
<head>

</head>
<body>
<!-- Navigation stuff -->

<!-- Content Area -->
<h2>Check this HTML5 video out!</h2>
<video height="270" width="480" id="myVideo">
<source src="/static/bunny.mp4" type="video/mp4">
<source src="/static/bunny.webm" type="video/webm">
</video>
<!-- More content -->

<!-- Right hand column -->

<!-- Footer stuff -->
<script src="/jwplayer/jwplayer.js" type="text/javascript"></script>
<script type="text/javascript">
// <![CDATA[
jwplayer("myVideo").setup(
{ modes:
[
{ type: 'html5' },
{ type: 'flash', src: '/jwplayer/player.swf' }
]
});
// ]]>
</script>
</body>
</html>

This in theory caters for the base position of native playback in all the mainstream browsers (Firefox & Opera – playing WebM; IE9, iOS, Safari & Android – playing MP4; Chrome – playing MP4 or WebM).

It also has the benefit that if JavaScript is enabled, JW Player will progressively enhance the player to ensure a consistent look-and-feel across all these browsers, plus provide a Flash fall-back for earlier versions of IE – playing the MP4.

Well that wasn’t too hard to implement… Except… What the…?!

After testing thoroughly and ensuring the videos play in all the browsers as expected I push my site live and I am greeted with… issues. Not only that, the worse kind of issues – inconsistent issues.

A selection of problems encountered include:

  • Chrome not playing the MP4, but playing the WebM. Safari plays the MP4
  • Firefox not playing WebM. Chrome plays the WebM
  • Safari not playing natively – rendering the Flash player
  • Safari not showing the player at all
  • IE7 & IE8 not showing the player at all
  • IE9 not showing controls
  • IE9 not showing anything

Given the specific nature of these issues, they should be reasonably easy to debug and determine a solution to.

However the following “generic” issues have also been experienced. These are much less obvious in terms of cause and can end up being responsible for hours of debugging frustration:

  • Previously “playable” video suddenly not loading – an error is presented
  • Video appearing to endlessly buffer – pressing pause and then resume presents a black screen
  • Video buffering for a long time before finally playing
  • Video plays on the first visit to a page, then fails on subsequent visits
  • Video doesn’t play on initial page load, but plays on refresh
  • Video playing with no audio
  • Audio playing with no video
  • Video playing and then stalling or playing out of sync with audio
  • Video format being played is not the expected one

Now, there are a number of phrases that might be used to describe this situation – the most likely in a business context being “show-stopper”. This may quickly be followed by the dreaded question “Is this the right solution for us?”.

In my opinion JW Player is indeed a very good solution – the support forums are a great means for getting issues resolved, and there is usually willing assistance with helping you understand the complexities of producing video for the web. However, as with many situations, knowing what question to ask in this context can sometimes make the difference between getting a speedy resolution versus a gradual increase in grey hairs and heightened blood pressure!

TIME FOR SOME FOR ANSWERS

Having experienced a number of these issues first-hand, and worked through them, I thought it would be useful to share my findings. The following pointers should cover off the specific issues detailed above and will also cater for some of the “generic” issues:

ENCODING

One of the most common stumbling blocks (and therefore most likely to resolve issues) is ensuring the encoding used is correct. It has been said many times before and I’m sure it will be said again – encoding is key. This is particularly relevant when it comes to producing an MP4 which is intended for playback on multiple devices – desktop browsers, iDevices, Android phones/tablets and recent Blackberry phones.

According to the JW Player documentation, the following specification should be adhered to:

> Container format: MP4, headers at the beginning of the file (for seeking)
> Video format: H.264, Baseline profile, 480×270 pixels, around 400/600 kbps (kilobits per second)
> Audio format: AAC, Low Complexity profile, 44.1 kHz stereo, 96 kbps

Also, within the support forums you will regularly see advice to “encode video to H.264 using Handbrake” and the JW documentation continues to say:

Handbrake has a built-in present called iPhone & iPod Touch, which has exactly the right settings.

Whilst good advice, this actually falls short of ensuring you get the correct results. One important option that is unchecked by default in all Handbrake profiles is the “Web optimized” option. Selecting this option reorders some of the metadata within the encoded video to the start of the container. This ensures the video can stream and allows the user to jump to specific points while the rest is downloading in the background.

If the metadata appears at the end of the video, the whole file needs to be downloaded before the video will start playing. I therefore highly recommend checking the “Web optimised” option when you encode. If you have files that are already encoded and are concerned that the metadata is not at the start, you can use another tool such as qt-faststart to move the metadata retrospectively.

More recent versions of Handbrake include the “iPhone 4”, “iPad” & “AppleTV” profiles which have the “Large file size” option checked by default. They also include the “Maximum B-Frames” set to “3” along with a host of other default settings. I would advise considering these settings further when deciding which profile to use.

For further detail regarding HTML5 video support, encoding options and much more useful information check out the excellent “Video on the Web” resource by Mark Pilgrim

SERVER SETTINGS – MIME-TYPES & GZIP

MIME-TYPES

For video to be correctly rendered in WebKit based browsers, the MIME-type provided by the server must correctly correspond to the encoding used.

Specifically:

  • Firefox requires “video/webm” to be set for the “.webm” filetype
  • IE9 requires “video/mp4” to be set for the “.mp4” filetype

In terms of what to include in the type attribute of the HTML source tag, I would suggest only including the MIME-type string – don’t bother with the “codecs” element as this is largely ignored anyway. Note: Including the MIME-type here DOES NOT negate the need to have the server configured correctly – they are not related.

If you experience problems with MP4 video playing on earlier version of Android you may wish to explore removing the type attribute for the MP4 source – as suggested in Peter Gasston’s post.

GZIP

In a bid to try and save bandwidth, some web hosts will gzip everything by default – including video files. In Firefox and Opera, seeking will not be possible or the video may not play at all if a video file is gzipped. If this is occurring it would be prudent to check your server / hosts and disable the gzipping of media files.

QUICKTIME & FLASH

It goes without saying that in order to play video via the Flash player, the browser needs to have the Flash plugin installed. Don’t assume this is the case for all browsers and try to provide a positive fall-back option – this also helps to debug issues.

Flash v9+ is required to playback H.264 encoded MP4’s.

A less obvious gotcha is the dependency of Quicktime for Safari when playing native video on Windows. Again support for this comes via a plugin, which is commonly not installed. Failure to have this available, plus the lack of the Flash plugin can actually lead to no player being rendered in Safari.

IE SPECIFICS

IE7 & IE8 don’t understand the native video & source tags and so will fall-back to Flash mode. However there are two factors that need to be in place in order for this to happen:

Firstly the Flash plugin needs to be available.

Secondly the use of a HTML5 Shim in order to “register” the availability of the video tag. JW Player cannot interrogate and build a configuration object if the video tag has not been “modernised”. This can be done by including a 3rd party HTML5 Shim library or more sensibly by loading the JW Player library in the head – JW Player will modernise the video tag if needed.

ADDITIONAL VIDEO PARAMETERS

The following parameters and their impact can often be overlooked when it comes to implementing a native video tag in conjunction with JW Player:

autoplay () : include this attribute (no value) to let the video start as the page gets loaded. Use sparsely, since this may frustrate your viewers. Note that it does not work on iOS.
controls () : include this attribute (no value) to display a simple controlbar, provided by the browser. The design of this controlbar varies per browser (which is a common issue JW Player resolves gracefully).
height (number) : height of the video on the page in pixels – is required.
loop (): Include this attribute to let the browser continuously repeat playback of the video.
poster (string): the url of a poster frame that is shown before the video starts. Can be any PNG, JPG or GIF image. By default, it is not set (i.e. no preview).
preload (‘auto’, ‘metadata’, ‘none’) : This attribute defines whether the entire video is loaded upon webpage load, or whether only the metadata is initially loaded. Or, you can choose to not load the video at all upon webpage load. The default (on most browsers) is metadata.
src (string) : The URL of the video to play. This is not required, since source files can also be listed using tags.
width (number) : width of the video on the page, in pixels. Is required.

The JW Documentation also states:

… Plus there’s the inevitable browser bugs (especially on devices) and different looking controls that cannot be styled.

The JW Player helps to fix all these issues. It sniffs out the contents of the video tag – the sources, as well as the poster, loop, autoplay, etc.). It also detects the browser capabilities and then uses JavaScript to, for example, work around bugs, add new features or embed a Flash version of the player in place of the tag.

Given these statements you might expect the controls, autoplay, loop and preload attributes to be directly controllable via the video tag and for the results to be consistent across browsers/devices.

Sadly this is not the case. Furthermore, these seemingly supplementary attributes are the reason behind most of the unexplainable “generic” issues detailed above.

Firstly it’s important to note that, contrary to what is stated, JW Player does not directly make use of these parameters.

It does have similar acting parameters which can only be included as part of the JavaScript setup configuration (controlbar, autostart, repeat and bufferlength) but these are not derived from the original parameters and are also not directly included as part of the newly generated JW video tag – they are implemented through pseudo JavaScript methods.

The second part of this is understandable as the JW Player needs to override the browsers built in functionality with it’s own implementation in order to provide consistency.

If JW Player determines that it should render in HTML5 mode, then it simply creates an empty video tag stub with none of these attributes included. This is because it also doesn’t set the source of the video (or src in the case of a single playable video or playlist file) until the user clicks the play button (or the file link in the playlist).

Coming back to the first part, why not allow the attributes to act as the configuration settings for the JW Player – even if they ultimately translate to JW’s own implementation? Surely this is a bug… Actually I believe it’s an oversight that LongTail Video are happy to brush under the carpet.

DIGGING A BIT DEEPER

Lets update my original code with these parameters and work through what happens:

<html>
<head>

</head>
<body>
<!-- Navigation stuff -->

<!-- Content Area -->
<h2>Check this HTML5 video out!</h2>
<video height="270" width="480" id="myVideo" preload="auto" controls autoplay>
<source src="/static/bunny.mp4" type="video/mp4">
<source src="/static/bunny.webm" type="video/webm">
</video>
<!-- More content -->

<!-- Right hand column -->

<!-- Footer stuff -->
<script src="/jwplayer/jwplayer.js" type="text/javascript"></script>
<script type="text/javascript">
// <![CDATA[
jwplayer("myVideo").setup(
{
modes:
[
{ type: 'html5' },
{ type: 'flash', src: '/jwplayer/player.swf' }
]
});
// ]]>
</script>
</body>
</html>

The most obvious thing to note given this configuration is that the native video tag will be interpreted and rendered well before the JW Player library is loaded and the setup call is made. This will result in the following:

  1. The native video placeholder being rendered according to the width & height specified
  2. Native video controls being displayed over the video
  3. The video will be buffered in accordance with the preload setting
  4. The video will start to play as soon as enough data is available to do so

Then when the JW Player library is loaded and the setup call is made[*] the following will happen:

  1. JW will “overwrite” the existing (already playing) video tag with it’s own player furniture comprising a number of nested div tags and a new, empty video tag
  2. The poster image will be displayed
  3. The JW controls will be displayed over the poster image
  4. The video will not automatically start to play

[*] Depending on what follows the video tag in the rest of the page – how long it takes to be rendered, and in the case of external scripts, how much they block – this could potentially be a number of seconds later.

Clearly this doesn’t result in a great user experience and depending on your requirements/flexibility there are things that can be done to make it better, however it does raise an interesting question – what *actually* happens to the video that is already playing when JW overwrites it?

You may rightly expect either the browser, or the JW embed process, to handle the clean up of the existing video – removing it from the DOM and wiping clean any future demands the resource may have on the browser, network or memory… You might therefore be surprised to learn that this is not the case!

Through my testing (yes – I ended up building a video testbed) I was able to determine the following:

If the native video is given enough time[1] to start doing “stuff”[2] before it is wiped out by the JW Embed process, the video will continue to exist in memory, can continue to make demands on the network and amazingly may even continue to play.

[1] Typically I found this to be anything over 0.5 sec.
[2] Either buffering data as a result of the preload attribute being set (or more likely not being set – see below) or downloading and playing as a result of the autoplay attribute.

The result of this situation leads to all manner of problems. I have actually seen, and more importantly can reproduce, the “phantom video” causing the following:

  • The newly JW embedded video delays playing until the “phantom” has finished downloading – misleadingly this can make you think the video encoding is wrong as it resembles the experience of having the metadata at the end of the file
  • The newly JW embedded video won’t play until the “phantom” has finished playing – resulting in a black screen and audio only
  • The newly JW embedded video buffers infinitely – this is as a result of the JW video believing it has buffered enough data to be able to play but actually it’s buffer being empty. It gets confused with the “phantom” video’s buffer which is ready to play – but never does
  • In the case of Firefox where it would natively play the WebM version, coupled with the default JW playback mode being “Flash-first” (supporting MP4), both videos are played simultaneously resulting in what appears to be echoey audio

Because the manifestation of these issues is closely related to the time taken between rendering a native video tag on the page and the JW Embedder overwriting it, you can now start to see how a page that one day has a working video, might suddenly start to exhibit inconsistent behaviour – maybe an external script library is blocking just a bit longer than normal (jQuery on a CDN for example) or you’ve upgraded to a new version of JW Player and the files are not cached the first time you revisit the page.

When you consider the negative impact preload and autoplay can have depending on your embedding approach, coupled with the fact these two attributes are not respected on the majority of mobile devices it becomes “understandable” why LongTail Video might prefer you not to use them – it just would be nice if the documentation were to accurately reflect this.

AND THE SOLUTION?

You may deduce that it’s as simple as to not include the preload or autoplay attributes in the native video tag. However when checking the current default values for preload (in the case that you don’t specify the attribute) I found the following:

Chrome Firefox Safari Opera <IE9 IE9 iOS 5 Android
auto "" auto metadata n/a metadata auto auto

Which suggests that most browsers will attempt to load the entire video upon webpage load – or more accurately, when the browser has enough information about the video tag to be able to render it – again this is not in line with what the JW documentation states.

THE RECOMMENDATION

Phew… that’s a lot to take on-board.

Here’s a quick summary of the approach I recommend in order to minimise the likelihood of problems when using JW Player to progressively enhance an HTML5 video tag.

  • Ensure your videos are encoded correctly
  • Ensure the MIME-types are set correctly on your server
  • Ensure GZIP is not enabled for media files
  • Load JW Library in the head of your web page – although the JW Documentation actually recommends this (in places) the supporting examples and suggestions in forums often overlook the importance of this
  • Don’t include the autoplay attribute in the native video tag
  • Include preload="none" in the native video tag
  • Include the setup script as close as possible inline after the video tag – in order to minimise the time it has to do “stuff” before it is overwritten
  • Include the JW equivalent versions of preload and autoplay in the setup configuration if really needed

HOLD ON, WHAT IF I ACTUALLY WANT TO preload OR autoplay…

Indeed… there is a use case scenario where the JW Player is not actually initiated (JavaScript is disabled) and so the native video tag (and it’s attributes) will be the mechanism used to render and play the video.

Following my recommendation unfortunately means that the native video will not preload or autoplay in this scenario.

On the one hand, maybe this is a small compromise to pay in order to overcome the wider issues of inconsistent video playback.

On the other hand, surely there is a way to clean up the “phantom video” issue and have the native video attributes *actually* drive the configuration of the JW player.

Oh, and while we’re at it, wouldn’t it be great if:

  • JW Player was fully configurable through HTML tags – including playlists – with no JavaScript knowledge required
  • Hybrid playlists could be built which were capable of merging YouTube playlists with individual videos – in Flash and HTML5 mode
  • And JW Player acted responsively within the body of the page or viewport of a mobile device whilst maintaining the correct aspect ratio

Well I thought it would be great. Which is why I’ve enhanced my extension to JW Player so that is does exactly that. You can find more details about this here.

WAIT NOW… WHAT’S THIS… JW6 IS COMING…

And unbelievably LongTail Video are removing support for embedding over a video tag!

Taken from the beta documentation:

JW6 supports many functionalities not supported by a video tag (e.g. Flash, RSS, YouTube, RTMP, VAST). Additionally, longer term promises of an inline video element (progressive enhancement, video SEO, accessibility) are not there yet. Therefore, JW6 does not support the enhancing of a video element yet.

Wow… After being leading advocates of the approach to progressively enhance HTML5 video tags and all the logical reasoning that goes with it, I find it amazing that LongTail Video can drop support for it in such a way.

JW6 supports many functionalities not supported by a video tag – yeah right, but a video tag supports more of these in a fall-back position than a div ever will!

A cynical person might think that by dropping support for this embed method, LongTail Video are looking to reduce the number of support issues that potentially fall under their remit. I imagine that what will actually happen when developers come to implement JW6 is they will simply wrap div‘s around their native video tags and target these div‘s instead – potentially creating more issues than solving. Only time will tell.

In the mean time, I’ve just added a new requirement to the JW HTML CONFIG JavaScript extension I’ve been developing – to support JW6!

 

Updated – 18th October 2012

Received an interesting response to this article from Jeroen @ LongTail Video today:

As James says at the bottom, all embed issues will be solved with JW6. It’s a full rewrite of our HTML5 mode. The MP4 encoding issues (MOOV atom, baseline, etc) remain though. Luckily, WebM seems about to leave the stage soon.

We specifically chose to not support the video element, because of all the issues we ran into with JW5. We do evangelize HTML5 video, for its longer-term promises. We do not support decorating the video element in JW6, because those promises have not yet been fulfilled. There’s no search/accessibility/fallback advantages for using a video element today. There’s also many reasons for preferring Flash in HTML5 browsers (codecs, streaming, security, performance, consistency, advertising, etc).

Over time, we WILL support decoration of video tags as an embed method. It’s just not yet feasible. We have two blog posts lined up for this, in which we’ll elaborate.

Firstly I’m guessing Jeroen actually means “…Ogg seems about to leave the stage soon…” not WebM.

Secondly, it’s interesting to note that JW6 has switched the default playback mode from Flash first in JW5 to HTML5 first – which conflicts with the idea that there are “… many reasons for preferring Flash in HTML5 browsers…”. HTML5 mode is all about presenting and decorating the native video tag.

For me, it still makes more sense to start with a native video tag, whilst providing good documentation (and even a code fix?!) to highlight and overcome the “Phantom Video” issue. This will at least ensure some accessibility and SEO benefits over and above an empty div tag – which relies on JavaScript enhancements to function at all.