Using HTML5 video events

HTML5 video events provide ways to streamline and add efficiency to your webpages.

  • Why use events?
  • Is my webpage ready yet?
  • Where am I?
  • What's that button do now?
  • Is it done yet?
  • Related topics

Why use events?

The HTML5 video object offers a number of events that can help simplify and enhance your webpage's content. Here you'll see examples that use events to check whether content is available, the state of video playback, and how to monitor the current playing position in a video.

Is my webpage ready yet?

For a webpage that uses video, there are two levels of "ready" that you are interested in; when the page elements have loaded, and when the content can play.

The most common first task in an HTML5 video page is to see whether the browser supports video. This is often done by checking to see whether the video element on the page was created, and whether a property required by the script is available. A script can only check for an element if the element has been loaded or created in the Document Object Model (DOM). A good way to check if the webpage elements are done loading is to use the DOMContentLoaded event on the document object. This event fires when the page elements have finished loading and the basic DOM is available. This example creates a handler for DOMContentLoaded that calls a webpage's "init()" function.

  //  When the HTML elements load, call init()
  document.addEventListener("DOMContentLoaded", init, false);
 
  //  Rotate the video by 30degrees when image is clicked
  function init() {
    var video = document.getElementById("theVideo");
    if (video) {
      var rotateVal = 0;       //  Global variable to hold current rotation value
      document.getElementById("rotateVideo").addEventListener("click", function () {
        rotateVal = (rotateVal += 30) % 360;  // Calculate the next value, but keep between 0 and 360
        var temp = "rotate(" + rotateVal + "deg)"; // Create a style string
        document.getElementById("theVideo").style.msTransform = temp;  // Set the style
      }, false);
    }
  }

The example's "init()" function encapsulates all the functionality of the script portion of the page.

Another way is to put the <script> section as done in the example for this topic. The HTML portion loads and then the script section loads. This ensures that all the HTML elements have loaded. If you load any content in the HTML section, you might have to use the onload event to check for completion, as media often takes longer than the elements to load.

The script section sets up several global variables, "video", "vLength", and "pgFlag." These variables provide the video object, the length of the currently loaded video (used for calculations later), and a flag used for progress tracking.

var video = document.getElementById("Video1");
var vLength;
var pgFlag = ""; // used for progress tracking

The video variable is then tested to see if the canPlayType property is available. If it is, the HTML5 video element is supported and all the other code is executed. If video isn't supported, the statement (video.canPlayType) returns false, and a message is displayed. With video support confirmed, the input field is enabled through the display style.

if (video.canPlayType) {   // tests that we have HTML5 video support

At this point, a file can be typed into the input field and loaded. Depending on where the video file is located, any network or server slowness might prevent the video from being ready when the rest of the page is. The following example uses the oncanplay event to tell when a video has loaded enough to start playing. When the oncanplay event fires, the handler displays the playback controls to signal that it's ready to play.

// content has loaded, display buttons and set up events
video.addEventListener("canplay", function () {
  document.getElementById("buttonbar").style.display = "block";
}, false);

When the video loads into the video object, one of the first things to load is the metadata, which contains information about the video. The following example uses the onloadedmetadata event to determine how long the video is. The onloadedmetadata event fires when the video object gets enough information about the content to know the duration.

//  display video duration when available
video.addEventListener("loadedmetadata", function () {
  vLength = video.duration.toFixed(1);
  document.getElementById("vLen").textContent = vLength; // global variable
}, false);

Where am I?

The last example showed how to get the duration or length, of a video after it loads. After a video starts playing, you can use the ontimeupdate event to get the current position in a video. The ontimeupdate event fires when the currentTime property changes. In the event handler, the value of currentTime is retrieved from the video object, and displayed. The currentTime property is a floating point variable that can take the decimal place out to 12 places. However, for performance purposes, the event is only fired four times a second in Windows Internet Explorer. For display in the example, the "toFixed()" method is used to round currentTime to one place. As the video is running, the current time is updated and displayed.

//  display the current and remaining times
video.addEventListener("timeupdate", function () {
  //  Current time  
  var vTime = video.currentTime;
  document.getElementById("curTime").textContent = vTime.toFixed(1);
  document.getElementById("vRemaining").textContent = (vLength - vTime).toFixed(1);
}, false);

The example also reports the remaining time by subtracting the current time from the duration.

What's that button do now?

A common trend in video player controls is to toggle buttons between two states, such as Play and Pause, or Sound and Mute. The example in Using JavaScript to control the HTML5 video player does this in the button handler. For example, when you click the Play button, the click handler checks the paused property and plays or pauses the video playback. It also swaps the button to pause text when the video is playing, and play text when the video is paused. This works most of the time, but if the video element has controls enabled, the two button settings can get out of sync. This example shows using the paused property in the play button handler.

                //  play video
                function vidplay(evt) {
                    if (video.src == "") {  // inital source load
                        getVideo();
                    }
                    button = evt.target; //  get the button id to swap the text based on the state                                    
                    if (video.paused) {   // play the file, and display pause symbol
                        video.play();
                        button.textContent = "||";
                    } else {              // pause the file, and display play symbol  
                        video.pause();
                        button.textContent = ">";
                    }
                }

A better way is to use the onpause and onplaying events to keep the buttons in sync. Unlike the previous example that only checks the paused property when the button is clicked, this next example toggles the buttons when the state of the video playback changes, regardless of how they got there.

//  paused and playing events to control buttons
video.addEventListener("pause", function () {
  document.getElementById("play").textContent = ">";
}, false);

video.addEventListener("playing", function () {
  document.getElementById("play").textContent = "||";
}, false);

Try the example at the end of this page and notice how the external buttons and the controls built into the video object stay in sync.

The same technique can be used with the onvolumechange event to control the graphic on the Mute button. Because there aren't discrete mute and volume events, this next example uses onvolumechange to handle both states.

video.addEventListener("volumechange", function () {
  if (video.muted) {
    // if muted, show mute image
    document.getElementById("mute").innerHTML = "<img alt='volume off button' src='mute2.png' />";
  } else {
    // if not muted, show not muted image
    document.getElementById("mute").innerHTML = "<img alt='volume on button' src='vol2.png' />";
  }
}, false);

In this example, when the onvolumechange event fires, an "if" statement tests the muted property. If the video object's sound track is muted, the mute graphic is displayed; otherwise, the sound graphic is displayed. As the graphic changes, so does the alt text to provide an accurate description for accessibility.

Note  All buttons, input elements, and the video element use the title attribute to provide a tooltip when a user hovers their mouse over the element. This practice also provides identification text for screen reader devices.

 

Is it done yet?

The HTML5 video player needs to buffer content for playing. If a video content is large, your page might need to manage playback and messaging to give the user a good experience. For example, if a download is taking too long, you can use events to alert the user that there is a problem, rather than the video just stopping without explanation. The onstalled, onwaiting, or onended can be used to determine action when a video is interrupted. The following table describes events that can be used to manage playback and your user's expectations.

Event Description
oncanplaythrough Fires when playback to the end of the file can be done without further buffering.
onloadstart Fires when Internet Explorer starts looking for media data. This happens when a video (or audio) resource is requested from a site, and only occurs one time per request.
onloadeddata Fires when media data is loaded at the current playback position. The video can start playing.
onended Fires when the end of playback is reached.
onemptied Fires when the video object is reset to its initial state.
onstalled Fires when downloading has been interrupted for more than three seconds. This can indicate a network problem.
onwaiting Fires when playback stops because the next frame of video isn't available (might be buffering).
onprogress Fires to indicate progress during media content downloading. Stops firing after download is complete.
ondurationchange Fires immediately after onloadstart and before onloadedmetadata.

 

This code sample is the complete code for the examples shown in this topic, and includes a section that shows the events that apply to downloading and buffering mentioned here.

Note  This sample uses images for sound on and sound off .

 

<!DOCTYPE html >

<html >
  <head>
    <title>Video events example</title>
    <!-- Uncomment the following meta tag if you have issues rendering this page on an intranet or local site. -->    
    <!-- <meta http-equiv="X-UA-Compatible" content="IE=edge"/> -->    
    </head>
    <body >        

    <div>
        <label>Type or paste a video URL: <br/>
        <input type="text" id="videoFile" style="width: 300px;"  title="video file input field" value="http://ie.microsoft.com/testdrive/ieblog/2011/nov/pp4_blog_demo.mp4" />        
        <button id="loadVideo" title="Load video button" >Load</button>
        </label>
    </div>    
    <video id="Video1" controls style="border: 1px solid blue;" height="240" width="320" title="video element">      
         HTML5 Video is required for this example
    </video>
    
    <div id="buttonbar" style="display: none; font-size:larger;")>
        <button id="restart" title="Restart button">[]</button> 
        <button id="slower" title="Slower playback button">-</button>
        <button id="rew" title="Rewind button" >&lt;&lt;</button>
        <button id="play" title="Play button">&gt;</button>
        <button id="fwd" title="Forward button" >&gt;&gt;</button>
        <button id="faster" title="Faster playback button">+</button>
        <button id="mute" title="Mute button" ><img alt="Volume on button" src="vol2.png" /></button>     
        <br />
        <label>Reset playback rate: </label><button id="normal" title="Reset playback rate button">=</button>           
        <br />
        <label>  Volume: </label>
            <button id="volDn"  title="Volume down button">-</button>
            <button id="volUp"  title="Volume up button">+</button>
        <br />
        <div id="status" >Length(seconds): <span id="vLen"></span> <br />
        Current time:  <span id="curTime" title="Current time"></span><br />   Remaining time: <span id="vRemaining" title="Remaining time"></span></div>
    </div>   
    <br/>  

    <div title="Error message area" id="errorMsg" style="color:Red;"></div>  
    <div title="Event status area" >
      <label>oncanplaythrough: </label><span class="stats" id="cpt"></span><br />
      <label>onloadstart: </label><span class="stats"  id="ls"></span><br />
      <label>onprogress: </label><span class="stats"  id="pg"></span><br />
      <label>onloadeddata: </label><span class="stats" id="ld"></span><br />
      <label>onended: </label><span class="stats" id="ndd"></span><br />
      <label>onemptied: </label><span class="stats" id="mt"></span><br />
      <label>onstalled: </label><span class="stats" id="stall"></span><br />
      <label>onwaiting: </label><span class="stats" id="waiting"></span><br />
      <label>ondurationchange: </label><span class="stats" id="dc"></span><br />    
    </div>

    <script>
        var video = document.getElementById("Video1");
        var vLength;
        var pgFlag = ""; // used for progress tracking
        if (video.canPlayType) {   // tests that we have HTML5 video support

          //  video button helper functions
          //  play video
          function vidplay(evt) {
            if (video.src == "") {  // inital source load
              getVideo();
            }
            if (video.paused) {   // play the file, and display pause symbol
              video.play();
            } else {              // pause the file, and display play symbol  
              video.pause();
            }
          }
          
          //  load video file from input field
          function getVideo() {
            var fileURL = document.getElementById("videoFile").value; // get input field                    
            if (fileURL != "") {
              video.src = fileURL;
              video.load();  // if HTML source element is used
              document.getElementById("play").click();  // start play
            } else {
              errMessage("Enter a valid video URL");  // fail silently
            }
          }


          //  button helper functions 
          //  skip forward, backward, or restart
          function setTime(tValue) {
            //  if no video is loaded, this throws an exception 
            try {
              if (tValue == 0) {
                video.currentTime = tValue;
              }
              else {
                video.currentTime += tValue;
              }

            } catch (err) {
              // errMessage(err) // show exception
              errMessage("Video content might not be loaded");
            }
          }

          // change volume based on incoming value 
          function setVol(value) {
            var vol = video.volume;
            vol += value;
            //  test for range 0 - 1 to avoid exceptions
            if (vol >= 0 && vol <= 1) {
              // if valid value, use it
              video.volume = vol;
            } else {
              // otherwise substitute a 0 or 1
              video.volume = (vol < 0) ? 0 : 1;
            }
          }
          //  button events               
          //  Play
          document.getElementById("play").addEventListener("click", vidplay, false);
          //  Restart
          document.getElementById("restart").addEventListener("click", function () {
            setTime(0);
          }, false);
          //  Skip backward 10 seconds
          document.getElementById("rew").addEventListener("click", function () {
            setTime(-10);
          }, false);
          //  Skip forward 10 seconds
          document.getElementById("fwd").addEventListener("click", function () {
            setTime(10);
          }, false);
          //  set src == latest video file URL
          document.getElementById("loadVideo").addEventListener("click", getVideo, false);

          // volume buttons
          document.getElementById("volDn").addEventListener("click", function () {
            setVol(-.1); // down by 10%
          }, false);
          document.getElementById("volUp").addEventListener("click", function () {
            setVol(.1);  // up by 10%
          }, false);

          // playback speed buttons
          document.getElementById("slower").addEventListener("click", function () {
            video.playbackRate -= .25;
          }, false);
          document.getElementById("faster").addEventListener("click", function () {
            video.playbackRate += .25;
          }, false);
          document.getElementById("normal").addEventListener("click", function () {
            video.playbackRate = 1;
          }, false);
          document.getElementById("mute").addEventListener("click", function (evt) {
            if (video.muted) {
              video.muted = false;
            } else {
              video.muted = true;
            }
          }, false);

          //  any video error will fail with message 
          video.addEventListener("error", function (err) {
            errMessage(err);
          }, true);
          // content has loaded, display buttons and set up events
          video.addEventListener("canplay", function () {
            document.getElementById("buttonbar").style.display = "block";
          }, false);

          //  display video duration when available
          video.addEventListener("loadedmetadata", function () {
            vLength = video.duration.toFixed(1);
            document.getElementById("vLen").textContent = vLength; // global variable
          }, false);

          //  display the current and remaining times
          video.addEventListener("timeupdate", function () {
            //  Current time  
            var vTime = video.currentTime;
            document.getElementById("curTime").textContent = vTime.toFixed(1);
            document.getElementById("vRemaining").textContent = (vLength - vTime).toFixed(1);
          }, false);
          //  paused and playing events to control buttons
          video.addEventListener("pause", function () {
            document.getElementById("play").textContent = ">";
          }, false);

          video.addEventListener("playing", function () {
            document.getElementById("play").textContent = "||";
          }, false);

          video.addEventListener("volumechange", function () {
            if (video.muted) {
              // if muted, show mute image
              document.getElementById("mute").innerHTML = "<img alt='volume off button' src='mute2.png' />";
            } else {
              // if not muted, show not muted image
              document.getElementById("mute").innerHTML = "<img alt='volume on button' src='vol2.png' />";
            }
          }, false);
          //  Download and playback status events.
          video.addEventListener("loadstart", function () {
            document.getElementById("ls").textContent = "Started";
          }, false);
          video.addEventListener("loadeddata", function () {
            document.getElementById("ld").textContent = "Data was loaded";
          }, false);

          video.addEventListener("ended", function () {
            document.getElementById("ndd").textContent = "Playback ended";
          }, false);

          video.addEventListener("emptied", function () {
            document.getElementById("mt").textContent = "Video reset";
          }, false);

          video.addEventListener("stalled", function () {
            document.getElementById("stall").textContent = "Download was stalled";
          }, false);
          video.addEventListener("waiting", function () {
            document.getElementById("waiting").textContent = "Player waited for content";
          }, false);
          video.addEventListener("progress", function () {
            pgFlag += "+";
            if (pgFlag.length > 10) {
              pgFlag = "+";
            }
            document.getElementById("pg").textContent = pgFlag;

          }, false);
          video.addEventListener("durationchange", function () {
            document.getElementById("dc").textContent = "Duration has changed";
          }, false);
          video.addEventListener("canplaythrough", function () {
            document.getElementById("cpt").textContent = "Ready to play whole video";
          }, false);
        } else {
          errMessage("HTML5 Video is required for this example");
          // end of runtime
        }
        //  display an error message 
        function errMessage(msg) {
          // displays an error message for 5 seconds then clears it
          document.getElementById("errorMsg").textContent = msg;
          setTimeout("document.getElementById('errorMsg').textContent=''", 5000);
        }
    </script>



  </body>
</html>

Adding an HTML5 video control to your webpage

Internet Explorer 10 Samples and Tutorials

Using JavaScript to control the HTML5 video player

HTML5 Audio and Video

Pausing or changing the volume of media when you leave the page