Embedding Flash video accessibly
A simple, unobtrusive, and lightweight method to embed Flash video accessibly into your page. Content in the HTML is replaced with a Flash inset only if both JavaScript and the minimum level of Flash are supported. Multiple Flash insets are also catered for. The method depicted here is a furtherance to that employed by Tesco Direct to deliver their TV adverts online.
The best media player out there is undoubtedly Jeroen Wijering's mediaplayer. Feature laden, accessible and skinable. At the time of writing version 4.2. To be honest it needs a tutorial in itself. I cannot recommend this player highly enough. If you're using anything else, change.
There are many advantages to this solution:
- The simplest of installation set-ups.
- Tests for the users Flash version, and only inserts if supported.
- Unobtrusive. No extra mark-up in the (X)HTML.
- Accessible with or with out JavaScript.
- Semantic W3C formal grammar, validates even after the Flash is embedded.
- Accessible, with or with out Flash.
- Very small footprint (2.59 KB).
- Multiple Flash insets per page.
- A cross-browser, cross-platform solution.
Caveat: It appears Firefox 3 has an issue playing video with Adobe's Flash Player v9. The recommended fix is to download Adobe's Flash player 10 beta. Rubbish if you ask me.
From an accessibility perspective there are two types of video:
- Essential page content. Which requires: An alternate video version(s), a text transcript, and captioning if you're really serious.
- A non-essential embellishment to the page content. Which only requires an image, with good alt text, as an alternative.
Both use the same JavaScript method presented but "essential content" has a little more XHTML.
Embedding Flash video example
Here's the example running on a bare bones demo page. There's a zipped complete set of the files and just the JavaScript used. The zipped set includes agressively minified versions. The smallest of which is only 2.59 KB.
I've still to add an audio description.
How it works
The method is extremely simple. Basically an image in the content is replaced by a video.
Once the page has completely loaded the script looks through all the images on the page and makes a list of those with a class name of img2flv. For each it replaces the content of the image container. The <div> in the example. All the variable parameters required are taken from the image and applied to the video player.
The XHTML
The video parameters are taken from the image in the html:
<div>
<img class="img2flv" src="example1.jpg" width="320" height="240" title="" alt="Example 1: Belly dance" />
<div class="altContent">
<p>Download <a href="example1.mp4">Belly dance video [MP4]</a> or <a href="example1.txt">Belly dance text transcript [TXT]</a>.</p>
</div>
</div>
When the video is a non-essential embellishment to the page content you can leave out the altContent div but ensure the image alt text is accurate. Otherwise please ensure there is an MP4 and TXT version of the content available.
The JavaScript
JavaScript constants
Some global constants are required:
var minFlash=8;
var img2flvClass="img2flv";
var altContentClass="altContent";
var flvPlayer="player.swf";
var playerSkin="snel.swf";
Where:
- minFlash=8 - Is the minimum version of the Flash player needed to run the video. I use the On2 VP6 codec for better quality and streaming which requires at least v8. Full screen requires version 9+.
- img2flvClass="img2flv" - The class name associated to any image which is to be replaced by a FLV video.
- altContentClass="altContent" - Class of alternate content div to display if Flash or JavaScript is unsupported.
- flvPlayer="player.swf" - The location and name of the FLV player. Used here is v4.2 of Jeroen Wijering player
- playerSkin="snel.swf" - The location and name of the player skin. Used here is Snel v1.0 by LongTail Video
Standard functions
A few of my personal standard functions to make life easier:
function $id(i){return(document.getElementById(i)?document.getElementById(i):false)}
function idExists(i){return($id(i)?true:false)}
function domFunctions(){return (document.getElementById&&document.getElementsByTagName)}
function isFlash(v){var t=20,i=0;if(navigator.plugins&&navigator.plugins.length){for(var x=0;x<navigator.plugins.length;x++){if(navigator.plugins[x].name.indexOf('Shockwave Flash')!=-1){i=parseInt(navigator.plugins[x].description.split('Shockwave Flash ')[1]);break}}}else if(window.ActiveXObject){for(var x=2;x<=t;x++){try{if(eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+x+"');"))i=x}catch(e){}}}return((i>=v)?i:0)}
/* author: Simon Willisons - http://simon.incutio.com/archive/2004/05/26/addLoadEvent */
function addLoadEvent(f){var o=window.onload;if(typeof window.onload!='function'){window.onload=f}else{window.onload=function(){o();f()}}}
Where:
- $id(i) - same as writing document.getElementById(i)
- idExists(i) - Checks an id exists returning true or false.
- domFunctions() - Checks DOM functions used are available.
- isFlash(v) - returns the flash version if it's >= v otherwise 0.
- addLoadEvent(f) - Allows for multiple window.onload events.
Flash media player object creation
Utilises player.swf v4.2 by Jeroen Wijering.
Requires the image and FLV to have the same name and be in the same location. Pass in the id of the html image. The video properties: width, height, location and name are extracted from it, as is name and location of the captions file if used.
function flashVideo(id){
var obj=$id(id);
if (obj.src){
var image=obj.src;
// apply image to background of parent container for a smooth changeover to video
$id(id).parentNode.style.background="url("+image+") no-repeat";
var f=image.substring(0,image.lastIndexOf("."))
var video=f+".flv";
var appWidth=obj.width;
var appHeight=obj.height;
// alternative content
var captions=f+".captions.xml";
var download=f+".mp4";
var altText=obj.alt;
var alt=$id(id).nextSibling.nextSibling;
var altContent=(alt && alt.className==altContentClass)?alt.innerHTML:"";
var parent=obj.parentNode;
if (video && image && parent && appWidth && appHeight && flvPlayer && isFlash(minFlash)){
The Flash variables
var flvVars='file='+video;
flvVars+='&displayheight='+appHeight;
flvVars+='&displaywidth='+appWidth;
flvVars+='&image='+image;
flvVars+='&autostart=false';
flvVars+='&controlbar=over'; // over/bottom/none
flvVars+='&screencolor=ffffff';
flvVars+='&skin=snel.swf';
// accessibility options
flvVars+='&link='+download;
flvVars+='&plugins=accessibility-1';
flvVars+='&captions='+captions;
flvVars+='&accessibility.fontsize=22';
The Flash object
var str='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version='+minFlash+',0,0,0" width="'+appWidth+'" height="'+appHeight+'">';
str+='<param name="movie" value="'+flvPlayer+'" />';
str+='<param name="flvQuality" value="high" />';
str+='<param name="allowfullscreen" value="true" />';
str+='<param name="flashvars" value="'+flvVars+'" />';
str+='<param name="wmode" value="transparent" />';
str+='<!--[if !IE]> <-->';
str+='<object data="'+flvPlayer+'" width="'+appWidth+'" height="'+appHeight+'" type="application/x-shockwave-flash">';
str+='<param name="flvQuality" value="high" />';
str+='<param name="allowfullscreen" value="true" />';
str+='<param name="flashvars" value="'+flvVars+'" />';
str+='<param name="wmode" value="transparent" />';
str+='</object>';
str+='<!-->';
str+='<p>'+altText+'</p>';
// place here if only required for accessibility
// str+=altContent;
str+='<![endif]-->';
str+='</object>';
// place here if always required (recommended)
str+=altContent;
Display alternate content if Flash unavailable then insert new content and close
}else{
// no flash, offer alternatives if available.
var str=parent.innerHTML;
}
parent.innerHTML=str;
}
}
Find the image(s) to replace
The image replacement function. It works generically by class name:
/* Parameters:
The class name for generic replacements.
The name of the function to build the Flash video object.
*/
function imageTo(classN,func){
var imgs=document.getElementsByTagName('img');
var imgIDs=new Array();
var c=0;
for (var i=0;i<imgs.length;i++){
if (imgs[i].className==classN){
if (!imgs[i].id){
imgs[i].id=classN+i;
}
imgIDs[c++]=imgs[i].id;
}
}
for (var i=0;i<imgIDs.length;i++){
func(imgIDs[i]);
}
}
This function scans through all the images and collates those with a specified class name. An id is assigned if not already present. Each id is then passed to a function which replaces the content.
Setting it all up:
If the required Dom functions are supported then run setup on page load.
function setup(){
imageTo(img2flvClass,flashVideo);
}
/* test dom functions used are supported */
if (domFunctions()){
addLoadEvent(setup);
}
Hiding the alternate content
Best practice states the alternate formats should always be visible.
Only if you really must hide the alternate versions, unless JavaScript or Flash are unsupported, then do it in this manner.
In the flashVideo function change the commented lines so:
// place here if only required for accessibility
str+=altContent;
str+='<![endif]-->';
str+='</object>';
// place here if always required (recommended)
// str+=altContent;
Update history
- 29th November 2008
- Upgraded the player to version 4.2 after the release of the accessibility plugin.
- Removed the necessity for the image to have an id.
- Added a background image to the container to allow for a smooth transition between image and video.
- Added alternate content files MP4 and text transcript.
- Added closed captioning.
- 22nd September 2008
- Original upload using version 3.12 of the flvplayer.
Further reading
- A List Apart article: Flash Embedding Cage Match by Bobby van der Sluis
- Perishable Press article: Embed Flash or Die Trying by Jeff Starr
- A List Apart article: Bye Bye Embed by Elizabeth Castro
- The fully featured swfObject Flash object embed method
- Object Paranoia by Gez Lemon
- Dutch Government video [English]
- Accessible video usage
- Making video accessible
Social links and email client: