Building a better HTML5 video player with Glow

Warning This article was written over six months ago, and may contain outdated information.

Last year I wrote a post (Build­ing HTML5 video con­trols with JavaScript) intro­duc­ing the HTML5 Media Ele­ments API and demon­strat­ing a sim­ple set of con­trols for play­ing video.

In this (some­what belat­ed) fol­low-up I’m going to explore build­ing a more inter­ac­tive set of con­trols using a JavaScript UI library; I’m going to use Glow, but it could eas­i­ly be adapt­ed to jQuery UI or similar.

You can see the play­er I’ll be using as an exam­ple here — although it must be stressed that it’s not a final ver­sion, for rea­sons I’ll cov­er at the end:

HTML5 & Glow Video Player

The markup

The video play­er itself is pret­ty straightforward:

<video autobuffer controls height="180" poster="BBB_poster.jpg" width="320"> 
  <source src="bbb.mp4" type="video/mp4">   
  <source src="bbb.webm" type="video/ogg">
  <source src="bbb.theora.ogg" type="video/ogg">
  <img alt="Film Poster" height="180" src="BBB_poster.jpg" width="320">
</video>

The video ele­ment has the controls attribute set, which we’ll remove with JavaScript lat­er. Note also the poster attribute, which dis­plays a still image until the video is ready to be played, at which point it dis­plays the first frame instead.

Next there are two source ele­ments, which serve the video to Fire­fox, Opera and Chrome (ogg) and Safari (mp4). Final­ly there’s an img ele­ment, which dis­plays if the brows­er does­n’t have video sup­port. Update: Added WebM support.

As for the con­trols, rather than list them here I’ll ask you to view the source to see what I’ve done. Basi­cal­ly I’ve added a bunch of form ele­ments; two input image types for the play and vol­ume icons, and two input text types for the dura­tion and vol­ume slid­ers. The lat­ter two aren’t nec­es­sary, but I want­ed them there for acces­si­bil­i­ty reasons.

The style

How I’ve styled the play­er does­n’t mat­ter too much; I’ve been influ­enced by the Quick­time play­er for the lay­out of the con­trols, but real­ly the CSS isn’t too impor­tant here. The only thing to note is that I’ve added some rules here for screen over­lays, which I’ll explain in due course:

.overlay { background-repeat: no-repeat; height: 180px; position: absolute; width: 320px; }
.paused { background-color: rgba(0,0,0,0.2); background-image: url('pause.png'); background-position: left bottom; }
.play { background-image: url('play.png'); background-position: center center; }

The JavaScript

You can see all the script I’ve used in the file video.js. I’ll go through some of the more impor­tant func­tions in turn.

Setting up

The first thing I’ve done is removed the native con­trols from the play­er for peo­ple who have JS enabled, so as not to pro­vide two con­flict­ing sets of controls:

video[0].controls = false;

Next I’ve defined some of the key vari­ables which I’ll be using through­out the script. One of those vari­ables, vol­umeS­lide, is assigned to one of Glow’s native wid­gets, a Slid­er; this will be used to con­trol the volume:

volumeSlide = new glow.widgets.Slider('#volume',{bindTo:'#vol_count', buttons:false, step:0.1, min:0, max:1, size:70, val:1});

You can see what all the options do in the Glow doc­u­men­ta­tion, but the key ones I’ve set are for it to appear in <div id=“volume”>, to have a min­i­mum val­ue of 0 and a max of 1, and to incre­ment in steps of 0.1. This match­es the vol­ume set­ting for the video element.

Waiting for the metadata

For the next step I’m going to cre­ate anoth­er slid­er, but this time for the duration/seek bar. In order to do this, how­ev­er, I need to query the video’s meta­da­ta to know what the dura­tion of the video is, and in Safari (which uses mp4 video) that does­n’t load before the rest of my JS has run.

To get around this I’ll poll the readyState attribute every half a sec­ond — with the setInterval func­tion — until it’s val­ue is at least 1, which means the meta­da­ta has loaded; once that’s done, I’ll load the slider:

t = window.setInterval(function() {
  if (video[0].readyState >= 1) {
    window.clearInterval(t);
    durationSlide = new glow.widgets.Slider('#vid_duration',{bindTo:'#duration_count', buttons:false, step:1, min:1, max:Math.round(video[0].duration-1), size:260, val:0});
    playVid();
  }
},500);

So you can see there that I’ve cre­at­ed the slid­er with a min­i­mum val­ue of 1 and a max­i­mum of the dura­tion of the video (in sec­onds), to incre­ment in steps of 1. After that the set­up is com­plete so I can begin the actu­al play­back functions.

Playback controls

There are too many func­tions to go into in detail, so I’ll quick­ly go through what hap­pens. First an over­lay is placed over the top of the video, which begins play­back when clicked. Next, event lis­ten­ers are added to the play but­ton, the vol­ume icon, and the vol­ume and dura­tion sliders.

The lis­ten­er on the play but­ton runs the func­tion play­Con­trol, which deter­mines the state of play­back (end­ed, paused or play­ing) and either plays or paus­es the video accord­ing­ly. It also updates the icon to reflect its action (if it is paused, the icon changes to a play icon, and vice ver­sa), and adds the pause over­lay onto the video screen when relevant:

function playControl() {
  if (video[0].paused === true) {
    video[0].play();
    /* Further functions here */
  };
} else if (video[0].ended === true) {
    video[0].play();
     /* Further functions here */
} else {
    video[0].pause();
     /* Further functions here */
}

There’s a func­tion called start­Count which uses setInterval to move the dura­tion slid­er along by one sec­ond while the video is play­ing, and a func­tion called pauseC­ount which uses clearInterval to pause.

The mute­Tog­gle func­tion does what you expect, and mutes the video; it also changes the vol­ume icon to show that state, and dis­ables the vol­ume slid­er while it is active.

A fur­ther func­tion, vol­ume­Icons, sets the state of the vol­ume icon; there are four pos­si­ble icon states, which are used depend­ing on the val­ue of the volume.

And the last func­tion, sec­ond­sTo­Time, con­verts sec­ond val­ues into hour/minute/second val­ues, allow­ing for the timer to be updat­ed. This is done every sec­ond by the start­Count func­tion, and also used for the func­tion which is called from the event lis­ten­er on the dura­tion slider.

That event is prob­a­bly worth look­ing at in detail:

glow.events.addListener(durationSlide,'slideStop',function(event){
  video[0].currentTime = event.currentVal;
  var currentSecs = secondsToTime(event.currentVal);
  vidTimer.text(currentSecs.h + ':' + currentSecs.m + ':' + currentSecs.s);
});

Using the slideStop event I can check when the slid­er has been moved, and first set the video to begin play­back from that point, then update the timer with the same val­ues. The vol­ume slid­er has a sim­i­lar event set on it.

Next steps

So as a reminder, here’s what I have so far:

HTML5 & Glow Video Player

Please bear in mind that this is very much a work in progress; I start­ed writ­ing the con­trols with­out Glow and intro­duced it at a lat­er stage, so some of the JavaScript could do with being optimised.

The markup for the con­trols could also do with some extra work to make them ful­ly acces­si­ble, which they prob­a­bly aren’t right now. Also, all of the dimen­sions are built around this video size, and won’t scale if dif­fer­ent sized videos are used.

I hope to return to this top­ic when I have more time, and cre­ate a robust set of video play­er con­trols which can be used in any site with­out extra work.

Please feel free to let me know if you encounter any bugs or odd­i­ties as you use this; it will help with the next stage of development.

11 comments on
“Building a better HTML5 video player with Glow”

  1. Hel­lo Peter,
    how are you ?

    Per­haps you should have a look at
    http://www.mediafront.org/project/osmplayer

    Keep up the good work ;-)

    Greet­ings,

    Frankie

  2. Hi Frankie,

    Yes, I’ve seen it, it’s a great project. Sub­lime is anoth­er sim­i­lar project: http://jilion.com/sublime/video

    But I like to play around on my own demo projects and see how it’s done :)

  3. […] 19. Build­ing a bet­ter HTML5 video play­er with Glow […]

  4. […] This is a tuto­r­i­al on build­ing an HTML5 video play­er in Javascript. It’s meant to give you a basic under­stand­ing of the dif­fer­ent options you have with the new video tag in HTML5, and the javascript need­ed to cre­ate some of the typ­i­cal video con­trols you’d find in oth­er play­ers. 19. Build­ing a bet­ter HTML5 video play­er with Glow […]

  5. […] 12. Tuto­r­i­al – Build­ing A Bet­ter HTML5 Video Play­er With Glow […]

  6. […] Build­ing a bet­ter HTML5 video play­er with Glow […]

  7. […] 19. Build­ing a bet­ter HTML5 video play­er with Glow […]

  8. […] Build­ing a bet­ter HTML5 video play­er with Glow (Bro­ken Links) […]

  9. […] Build­ing a bet­ter HTML5 video play­er with Glow (Bro­ken Links) […]

  10. Thanks Peter, my prob­lem is now solved.

  11. […] Build­ing a bet­ter HTML5 video play­er with Glow […]