There is currently (mid-2010) a lot of work going on at the various standards groups to add much-needed accessibility tools to all the new features that are becoming available with HTML5. One such initiative is to add subtitles to the video tag, and there has been considerable progress earlier this year with proposed standards - see the WhatWG proposal here - and here is an older version of the proposal at the W3C.
ginger's thoughts has a very good article about the proposed specs and a descriptive example of what the code for this extension will look like for the web developer.
While it is possible that we will see first experimental implementations of media text associations in beta versions of browsers this year, I'd be surprised if we can get to a majority of shipping browsers supporting these features before 2012. That is still quite a while away, but HTML5 video is certainly not standing still - we already see major sites switching to HTML5 video right now.
Now this IS an accessibility problem. In many countries websites are required by law to offer reasonable accessibility features, and one would hope that video subtitles are considered "reasonable" in 2010. Here is a solution:
VideoSub - a standards compliant way to add video subtitles to HTML5 video tags.
Features:
- Standards compliant - follows the draft specification for Media Text Associations. Just add <track> tags to your videos
- No coding required - just include MooTools and VideoSub on a page with video tags
- Handles multiple videos on a single page
- Detects browser support for <track> tags and will stay out of the way if the browser can handle subtitles
- Works with standard .SRT subtitle files (WebVTT support is planned)
- Supports seeking in the video
Please Note: As of early 2011, there has been a major shift in the proposed standard of the track element to a new subtitle format call WebVTT (link to WHATWG proposal excerpt). This format is new and there are unfortunately no valid and complete examples of a WebVTT file that I am aware of. For now I would recommend to continue using SRT files in combination with this library, since WebVTT will most likely not be implemented until sometime in 2012. I will update this library with WebVTT support as soon as it seems reasonably certain that the proposed standard will not shift any longer.
Lets get the show on the way:
You may also be interested in some of my other articles around HTML5, CSS3 and JavaScript.
Example
Here is a simple example of a HTML5 video tag with a <track> tag. VideoSub finds the video on pageload and loads the subtitle file which will then automatically be displayed when the video is played. Also check out what happens when you move the playhead with the mouse.
Code
Here is the code for the web developer who just wants this to work:
That's all you need! And here's the code of the VideoSub library if you are interested:
VideoSub v0.9.6:
// workaround to add video events for MooTools (http://www.chipwreck.de/blog/2010/03/02/html-5-video-mootools/), updated for MooTools 1.3
var media_events = {
loadstart: 2, progress: 2, suspend: 2, abort: 2,
error: 2, emptied: 2, stalled: 2, play: 2, pause: 2,
loadedmetadata: 2, loadeddata: 2, waiting: 2, playing: 2,
canplay: 2, canplaythrough: 2, seeking: 2, seeked: 2,
timeupdate: 2, ended: 2, ratechange: 2, durationchange: 2, volumechange: 2
}
Element.NativeEvents = Object.merge(Element.NativeEvents, media_events);
var media_properties = [
'videoWidth', 'videoHeight', 'readyState', 'autobuffer',
'error', 'networkState', 'currentTime', 'duration', 'paused', 'seeking',
'ended', 'autoplay', 'loop', 'controls', 'volume', 'muted',
'startTime', 'buffered', 'defaultPlaybackRate', 'playbackRate', 'played', 'seekable'
];
// check for video tags and show subtitle track if the browser doesn't know how
function videosub() {
// detect media element track support in browser via the existence of the addtrack method
var myVideo = document.getElementsByTagName('video')[0];
tracksupport = typeof myVideo.addtrack == "function" ? true : false;
if (!tracksupport) { // browser has no clue, let's help
// first find all video tags
videos = $$(document.getElementsByTagName('video'));
videos.each(function(el) {
// find track tag (this should be extended to allow multiple tracks and trackgroups) and get URL of srt file
subtitlesrc = el.getChildren('track').get('src');
if (subtitlesrc != '') { // we have a track tag and assume it's subtitles (should be extended to parse role)
var videowidth = el.get('width'); // set subtitle div as wide as video
var fontsize = 12;
if (videowidth > 400) {
fontsize = fontsize + Math.ceil((videowidth - 400) / 100);
}
var videocontainer = new Element('div', { // new container for video and subtitle
'styles': {
'position': 'relative'
}
});
videocontainer.wraps(el); // wrap the existing video into the new container
var subcontainer = new Element('div', { // subtitle bar
'styles': {
'position': 'absolute',
'bottom': '34px',
'width': (videowidth-50)+'px',
'padding': '0 25px 0 25px',
'text-align': 'center',
'background-color': 'transparent',
'color': '#ffffff',
'font-family': 'Helvetica, Arial, sans-serif',
'font-size': fontsize+'px',
'font-weight': 'bold',
'text-shadow': '#000000 1px 1px 0px'
}
});
subcontainer.addClass('videosubbar');
subcontainer.inject(videocontainer , 'bottom');
// called on AJAX load onComplete (to work around element reference issues and closures)
el.update = function(req) {
el.subtitles = new Array();
records = req.split('\n\n');
var r = 0;
records.each(function(record) {
el.subtitles[r] = new Array();
el.subtitles[r++] = record.split('\n');
});
}
// load the subtitle file
el.myRequest = new Request({
method: 'get',
url: subtitlesrc,
onComplete: el.update
});
el.myRequest.send();
el.subcount = 0;
// add event handler to be called when play button is pressed
el.addEvent('play', function(an_event){
el.subcount = 0;
});
// add event handler to be called when video is done
el.addEvent('ended', function(an_event){
el.subcount = 0;
});
// add event handler to be called when the video timecode has jumped
el.addEvent('seeked', function(an_event){
el.subcount = 0;
while (videosub_timecode_max(el.subtitles[el.subcount][1]) < this.currentTime.toFixed(1)) {
el.subcount++;
if (el.subcount > el.subtitles.length-1) {
el.subcount = el.subtitles.length-1;
break;
}
}
});
// add event handler to be called while video is playing
el.addEvent('timeupdate', function(an_event){
var subtitle = '';
// check if the next subtitle is in the current time range
if (this.currentTime.toFixed(1) > videosub_timecode_min(el.subtitles[el.subcount][1]) && this.currentTime.toFixed(1) < videosub_timecode_max(el.subtitles[el.subcount][1])) {
subtitle = el.subtitles[el.subcount][2];
}
// is there a next timecode?
if (this.currentTime.toFixed(1) > videosub_timecode_max(el.subtitles[el.subcount][1]) && el.subcount < (el.subtitles.length-1)) {
el.subcount++;
}
// update subtitle div
this.getNext('div').set('html', subtitle);
});
}
});
}
}
function videosub_timecode_min(tc) {
tcpair = tc.split(' --> ');
return videosub_tcsecs(tcpair[0]);
}
function videosub_timecode_max(tc) {
tcpair = tc.split(' --> ');
return videosub_tcsecs(tcpair[1]);
}
function videosub_tcsecs(tc) {
tc1 = tc.split(',');
tc2 = tc1[0].split(':');
secs = Math.floor(tc2[0]*60*60) + Math.floor(tc2[1]*60) + Math.floor(tc2[2]);
return secs;
}
window.addEvent('load',videosub);
There are some code comments in the library that should help if you want to modify the code - I'm sure somebody will modify it for jQuery or add styling options for the subtitles... :-)
Update: ...and we have a jQuery port! The port called jquery-videosub by Max Wheeler can be found on github.
Limitations for version 0.9.6:
- Only works with SRT format subtitles - I will add WebVTT support once the new subtitle standard has reached maturity
- Only supports a single <track> tag, ignores any further tracks after the first one in a video tag
- Ignores "kind" property of tracks
Download
VideoSub is Freeware, Attribution Appreciated.
Requirements: You will also have to include MooTools v1.3 or up, get the latest version here.
Version History:
v0.9 (June 24, 2010): Initial public version of VideoSub
v0.9.5 (June 26, 2010): Added font scaling for videos that are more than 400 pixels wide
v0.9.6 (February 10th, 2011): Updated VideoSub to work with MooTools 1.3
JavaScript:
HTML: