HTML5 Tutorial – Custom Controls for Multimedia

imageWhen you display video in HTML5, you have may want to display a set of controls to the user. The HTML5 video tag has a control attribute that lets you display the controls that come with the browser.

But you may want to build custom controls using its media API, and the media events. Play, pause, and seek in the entire video, change the volume, mute, change the playback rate (including going into negative values).

This post shows how you can build a custom media player using different the media API attributes, events, and methods.

Getting Started

To get started, you begin with a video element.


<!DOCTYPE html>
<html>
<head>
<title>Popeye for President</title>
</head>
<body>
<video width="320" height="240" controls>
<source src="video/PopeyeForPresident_qtp.mp4" type="video/mp4">
<source src="video/PopeyeForPresident_qtp.ogv" type="video/ogg">
Your browser does not support HTML5 MPG4 video.
</video>
</body>
</html>

The controls attributes remains for the use case of when a user has JavaScript turned off, your user will still work with the browser’s default control set.

So we will need to turn off the video. Once the page has been loaded, you can turn off the controls by setting the controls attribute to false.


// Turn off the default controls
cartoon.controls = false;

Play and Pause

Let’s add a button to play and pause.

<https://gist.github.com/devdays/7c3a869c884e7fa316e4

And then you can toggle the button to show Play or Pause and to set the video to play or pause.


playpause.addEventListener("click", function () {
if (cartoon.paused || cartoon.ended) {
playpause.title = "Pause";
playpause.innerHTML = "Pause";
cartoon.play();
}
else {
playpause.title = "Play";
playpause.innerHTML = "Play";
cartoon.pause();
}
});

The button’s default text is “play.” When the button is clicked for the first time, the video will start playing and the button’s text will be changed to “pause.” Subsequently, when the pause button is clicked, the video will pause and the button’s text will be changed back to “play.”

The Pattern

The remaining functionality that you can add follows the same basic format:

  1. Listen for an event from the video element.
  2. Check the element’s status.
  3. Then act on it via API methods.

Volume and Mute

To add a volume control, you’ll use one of the new HTML5 input types: range. This input type is usually rendered by the browser as a slider, which your user can move.

You specify the minimum and maximum values for the range input via the min and max attributes. You use the step attribute to set the amount you want the slider’s value to change when the slider’s position changes. To create a volume control slider with a range between 0 and 1, and a step size of  0.1.


<input id="volume" min="0" max="1" step="0.1" type="range" />

And then provide an event handler for the slider’s change event.


volume.addEventListener("change", function () {
cartoon.volume = volume.value;
}, false);

And then a button to mute.


<button id="mute">Mute</button>

With code to perform the mute.


mute.addEventListener("click", function () {
cartoon.muted = !cartoon.muted;
}, false);

This listens for the mut button’s click event, and then responds by setting the video element’s (Boolean) muted attribute to be the opposite of its current value.

Progress Bar

Next we define a progress bar. You can create a progress bar using a span that we will color using CSS.


<div id="progressBar">
<span id="progress"></span>
</div>

With some CSS to shade it in as the video plays.


#progressBar {
border: 1px solid #aaa;
color: #fff;
width: 295px;
height: 20px;
}
#progress {
background-color: maroon;
height:20px;
display: inline-block;
}

Finally, we add some script that listens to the video’s timeupdate event.


cartoon.addEventListener("timeupdate", function () {
var value = 0;
if (cartoon.currentTime > 0) {
value = Math.floor((100 / cartoon.duration) * cartoon.currentTime);
}
progress.style.width = value + "%";
}, false);

It checks the value of the video element’s currentTime attribute, which defines the current playback position, in seconds. If currentTime is greater than 0, and therefore the video has advanced, it calculates the current progress as a percentage using the video element’s duration attribute, which contains the video’s total length in seconds. Finally, it sets the CSS width of the progress span to this calculated value.

Best Practice

The media element API defines a number of events that you can use in implementing a media player. For a complete list, see the W3C’s summary of media element API events.

When you’re adding custom controls, it’s a best practice to listen for some of the available events to make sure your controls are always synchronized with the state of the video.

A user might reenable the brower’s default controls and use them to interact with the video. For example, in Firefox, a user can right-click the video, select Show Controls, and click Play or Pause. If a user did this and started a video playing, the text on the play/pause button that you created would no longer be correct.


cartoon.addEventListener('play', function () {
playpause.title = "Pause";
playpause.innerHTML = "Pause";
}, false);
cartoon.addEventListener('pause', function () {
playpause.title = "Play";
playpause.innerHTML = "Play";
}, false);

Completed Sample Code

Here’s a listing of the completed video sample code.


<!DOCTYPE html>
<html>
<head>
<title>Popeye for President</title>
<style>
#progressBar {
border: 1px solid #aaa;
color: #fff;
width: 295px;
height: 20px;
}
#progress {
background-color: maroon;
height: 20px;
display: inline-block;
}
</style>
<script>
window.addEventListener("load", function () {
// Turn off the default controls
cartoon.controls = false;
playpause.addEventListener("click", function () {
if (cartoon.paused || cartoon.ended) {
playpause.title = "Pause";
playpause.innerHTML = "Pause";
cartoon.play();
}
else {
playpause.title = "Play";
playpause.innerHTML = "Play";
cartoon.pause();
}
}, false);
volume.addEventListener("change", function () {
cartoon.volume = volume.value;
}, false);
mute.addEventListener("click", function () {
cartoon.muted = !cartoon.muted;
}, false);
cartoon.addEventListener("timeupdate", function () {
var value = 0;
if (cartoon.currentTime > 0) {
value = Math.floor((100 / cartoon.duration) * cartoon.currentTime);
}
progress.style.width = value + "%";
}, false);
cartoon.addEventListener('play', function () {
playpause.title = "Pause";
playpause.innerHTML = "Pause";
}, false);
cartoon.addEventListener('pause', function () {
playpause.title = "Play";
playpause.innerHTML = "Play";
}, false);
});
</script>
</head>
<body>
<video id="cartoon" width="320" height="240" controls>
<source src="video/PopeyeForPresident_qtp.mp4" type="video/mp4">
<source src="video/PopeyeForPresident_qtp.ogv" type="video/ogg">
Your browser does not support HTML5 MPG4 video.
</video>
<div id="controls">
<button id="playpause" title="play">Play</button>
<input id="volume" min="0" max="1" step="0.1" type="range" />
<button id="mute">Mute</button>
</div>
<div id="progressBar"><span id="progress"></span></div>
</body>
</html>

Even More Events and API

There are more elements and settings. For a demo, see HTML5 Video Events and API

Here are some commonly used properties.

  • currentTime. Returns the official playback position, in seconds. Can be set, to seek to the given time.
  • playbackRate. Returns the current rate playback, where 1.0 is normal speed. Can be set, to change the rate of playback.
  • volume. Returns the current playback volume multiplier, as a number in the range 0.0 to 1.0, where 0.0 is the quietest and 1.0 the loudest. Can be set, to change the volume multiplier.
  • duration. Returns the difference between the earliest playable moment and the latest playable moment (not considering whether the data in question is actually buffered or directly seekable, but not including time in the future for infinite streams). Will return zero if there is no media

Here are some commonly used events.

  • playing. Occurs when playback of media is ready to start after having been previously paused ended and when the media has stopped playing as it has finished.
  • timeupdate. Occurs when the media’s current playback position has changed.
  • play. Occurs when the media that was previously paused is no longer paused and playback has resumed.
  • pause. Occurs when the pause() method has returned and the media has been paused.
  • volumechange. Occurs when the media’s volume or muted attribute has changed.

Full Screen Support

Ok. We know you want to empower your user to make the video go full screen.

As of the time of the writing of this post, HTML 5 does not provides a way to make a video full screen. But there is the a new Full Screen specification that includes requestFullScreen function that allows arbitrary elements (including <video> elements) to be made full screen.

See caniuse.com to see if the browser you are targeting supports Full Screen API.

References

Sample Code

Sample code is available in the DevDays GitHub repository. See https://github.com/devdays/html5-tutorials