HTML5 Video and History: Features Users Can Really See

Wallace B. McClure | August 22, 2013

Download the Code Sample

 

Who hasn’t started looking at the mobile Web and HTML5—features like the viewport, new HTML5 controls, geolocation and many others that are part of smartphones, tablets and advanced browsers? With these features, developers have started to provide users with fairly common, new input controls; jQuery Mobile features; location and mapping; and much more. In this article, I describe two features that you might not be familiar with: the <video> tag and Web history. The <video> tag lets you display video without the need for plug-ins like Flash. Web history allows users to use the Back button to return to the previous page in an AJAX application.

Note: The APIs for HTML5 vary slightly across different versions of browsers and different implementations. Because HTML5 is still in the recommendation phase at the W3C, think of it as a draft at this point. Because these APIs may change before they become a final standard, I cover only the version of HTML5 implemented in Internet Explorer 10. Every opportunity will be made to test the code across other browsers to verify that it works.

The <video> Tag

If a picture is worth a thousand words, video must be worth a whole lot more. Video has been integrated into Web sites large and small. I love the Yahoo! Finance site, for example, and listen to numerous news reports.

Almost all of the video on sites is presented through the Flash browser plug-in. Unfortunately, browser plug-ins tend to be unreliable, and Flash is no exception. With an aim to limit the need for browser plug-ins, the <video> tag has evolved to enable the display of video directly in browsers. The biggest advantage of this evolution is that the <video> tag is integrated into browsers and into CSS and JavaScript, and it’s seen rapid uptake by the various browser manufacturers in their mobile and desktop versions.

<video> Markup

Before looking at a basic example of the <video> tag, we need to review the problem that arises because video can be saved in various formats. When files are played, the video content must be decoded, which is done through a codec. Unfortunately, browser and hardware vendors support different decoding formats. For example, Microsoft and Apple provide codecs for MP4. Google has refused to support MP4 because of the licensing and royalty requirements and instead provides codecs for its own format, WEBM. But Microsoft and Apple don’t provide support for WEBM. Thankfully, there’s a solution. The <video> tag supports having multiple video files associated with it by using the src attribute.

<video> Attributes

The<video> tag has a number of attributes that you can use to configure it and provide the user with an improved experience. These attributes (defined by the W3C) include:

  • Autoplay. Providing this attribute results in the video player automatically playing the video. The attribute can be provided alone or as autoplay=“autoplay”.
  • Preload. Provides a suggestion to the browser about whether to load the video file before it’s played. The values for the attribute are:
    • None. Hints to the browser not to preload the file, which can mean that the user is not expected to play the file or that download traffic should be minimized. This value is very important in a mobile environment.
    • Metadata. Hints to the browser that the user will most likely not play the file. However, downloading certain metadata is a good idea. This metadata may contain video dimensions, an initial frame, video length and other information.
    • Auto. Hints that the user is likely to view the video and that it’s acceptable to optimistically download it.
  • Controls. Instructs the browser to display a user interface for controlling the playback. This attribute can also be provided as controls=“controls”)
  • Loop. Instructs the browser to loop through the video. When the end of the video is reached, the video will start again from the beginning.
  • Poster. Has the browser display an image before the video is displayed—while no video data is available. The attribute is used as poster=”image.png”; the value is any valid URL.
  • Height. Provides a non-negative integer that represents the height of the video frame.
  • Width. Provides a non-negative integer that represents the width of the frame.
  • Muted. Sets the audio channel of the video to its default state. This attribute can also be provided as muted=“muted”)
  • Mediagroup. Instructs the browser to link multiple audio and video streams. This attribute is provided as mediagroup=“name”.
  • SRC. Defines the URL of the video. Thankfully, the <source> tag can be used to define alternative video sources depending on the browsers used as well as the codecs installed on the local system.

Now, let’s look at an example that demonstrates the following behaviors.

  • Video controls are displayed.
  • The onclick event is called when a user clicks the video.
  • A poster is displayed before the video runs.
  • The browser determines the video file that it can use via the <source> tag and src attribute. The browser literally starts at the first file in a list and goes through the list until it detects a file that it can display.

Here’s the sample code:

<video controls="controls" id="vp" onclick="this.play()"
  poster="Images/BasketballExampleClip.png"  width=”600”>
  <source src="video/BasketballExample.mv4" />
  <source src="video/BasketballExampleClip.mp4" />
  <source src="video/BasketballExampleClip.webm"  />
  <source src="video/BasketballExampleClip.ogv" />   
  <source src="video/BasketballExampleClip.ogv" />   
</video>

The output will look something like Figure 1. In this image, the video frame is larger than the default because the code uses the width attribute and the controls are visible. Also, if the video is paused, clicking any part of the video will cause the video to play.

A Simple Video Page
Figure 1. A Simple Video Page

Mimetypes and File Access

If you download the previous code and run it locally in Visual Studio, the <video> tag will most likely not work. The Visual Studio Web Development Server (also known as Cassini) does not appear to have the appropriate mimetypes, and adding mimetypes to Cassini is not possible. As a result, developers need to test their code on the server-based IIS or IIS Express. Doing so requires a change within the web.config. Add mimetypes by inserting the following lines:

<system.webServer>
  <staticContent>
    <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
    <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
    <mimeMap fileExtension=".webm" mimeType="video/webm" />
    <mimeMap fileExtension=".m4v" mimeType="video/m4v" />
  </staticContent>
</system.webServer>

In this configuration, the mimetypes for the MP4, OGV, WEBM, and M4V video types are added to the Web server for serving static content.

Along with thinking about mimetypes, you also need to consider accessing the files themselves. It’s entirely possible to use the path from the display file to the video file. My examples use this method for simplicity. However, if the path to the files changes, a modification is needed. To get around this problem in Razor, your code can use the @Href method to access the video file within the <video> tag, like this:

<video id="vid"  controls onclick="this.play()" 
    poster="Images/BasketballExampleClip.png"
  width="600">
    <source src="@Href("~/video/BasketballExampleClip.mp4")" />
    <source src="@Href("~/video/BasketballExampleClip.m4v")" />
    <source src="@Href("~/video/BasketballExampleClip.webm")" />
    <source src="@Href("~/video/BasketballExampleClip.ogv")" />
</video>

Methods and Properties

The <video> tag has a set of methods and properties that you can use to programmatically change the behavior of the tag and its controls and also to interact with other elements on an HTML page. These methods and properties include:

  • canPlayType. Tests the tag to determine whether there is support for HTML5 video.
  • currentTime. Gets the current position within the video.
  • muted. Used to determine whether the video’s audio is currently muted.
  • pause(). Pauses the video.
  • paused. Used to determine whether the video is paused.
  • play(). Begins playing the video.

Events

The <video> tag’s events include (but are not limited to) the following:

  • canplay. Used to determine when enough of a video has been loaded to begin playing it.
  • loadedmetadata. Fires when the video object obtains the duration of the video.
  • playing. Fires when the video object begins playing.
  • volumechange. Used to determine when the volume changes.

Note: For a longer list of the properties, methods, and events of the <video> tag, consult the references at the end of this article.

Enhancing the User Interface

Now let’s take a look at improving the user interface. The following sample code creates four buttons and assigns event handlers to them. These buttons allow a user to play, pause, fast forward 5 seconds, and rewind 5 seconds. The results of this code are shown in Figure 2.

Some things to note are:

  • The volume of the <video> tag can be manipulated via the .volume property.
  • The video can be fast-forwarded and rewound by updating the .currentTime property. The value is provided in seconds. The video tag handles the situation where changing the currentTime property would result in the video moving between two frames in the video. You don’t need to worry about that.
<input type="button" id="beginPlay" value="Begin Play" 
    onclick="BeginPlay()" />
<input type="button" id="pausePlay" value="Pause Play" 
    onclick="PausePlay()" />
<input type="button" id="revPlay" value="<< Rewind" 
    onclick="revPlay()" />
<input type="button" id="ffPLay" value="Fast Forward >>" 
    onclick="ffPlay()" />
<script type="text/javascript">
  var vid = document.getElementById("vp");
  vid.addEventListener('canplay', function (e) {
    this.volume = 0.5;
    this.play();
    }, false);
    vid.onplay = function () {
    }
    vid.onpause = function () {
    }
    vid.onplaying = function () {
    }
    function BeginPlay() {
      vid.play();
    }
    function PausePlay() {
      vid.pause();
    }
    function ffPlay() {
      if ((vid.currentTime != null) && (vid.playing)) {
        var ct = vid.currentTime;
        vid.currentTime = ct + 5;
      }
    }
    function revPlay() {
      if ((vid.currentTime != null) && (vid.playing)) {
        var ct = vid.currentTime;
        vid.currentTime = ct - 5;
      }
    }
</script>

Buttons Created to Control a Video in Desktop Internet Explorer
Figure 2. Buttons Created to Control a Video in Desktop Internet Explorer

Note: In my sample code, I show different ways of doing things. For example, I wire up some events by using an assignment of an event. In other cases, I use the addEventListener syntax available in the DOM. I do this to show options and not to show favoritism for one mechanism over another.

Learning History’s Lessons

Browsers have had the ability to go backward and forward between various pages since the beginning of the Web, and developers have been able to interact, change, and manage the browser URL for years. With the advent of AJAX, however, Web pages could change fairly dramatically without sending a full refresh of the page. This resulted in browser URLs that did not necessarily change with AJAX calls, and from a user’s standpoint, this behavior created a problem:

  1. User lands on page 1.
  2. User navigates via a link to page 2.
  3. While on page 2, the user performs an AJAX operation.
  4. The user clicks the Back button. The user thinks this action will undo the AJAX operation and the user will be presented with page 2 as it initially appeared. Unfortunately, the user is presented with page 1, which is most likely not what the user expected.

How can developers solve this problem? With ASP.NET 3.5 Service Pack 1, the ASP.NET team came out with a great solution. They could create a new URL and hold some type of state information in the URL. However, this solution raised issues regarding support for all the myriad of browsers in the marketplace. The W3C stepped into this scenario and defined the HTML5 History API.

The History API is defined by two methods/events:

  • History.pushState. As its name implies, pushState will push some historical information onto a stack. It takes three parameters, of the form history.pushState(state, title, url).
    • State can be any valid JSON data. This is the data that will be passed back to the popState event.
    • Title is a string. Some older browsers may not properly support the title parameter, so it can also be stored in the state.
    • URL is any valid URL. Once pushState is called, the URL in the location bar will be updated. This becomes helpful when users want to copy the URL in their browser and send it to someone else.
  • popState. The popState event pulls the most recent data off of the History stack in the browser.

Let’s look at some simple code that puts this to use. In this example, a page is loaded and the time is displayed in a label. When the user clicks a button, the time in the label is updated. Along with the time being updated in the <span> tag, the browser’s current state is pushed to the History object, the URL hash is updated, and the browser’s Back button is now active.

<span id="current"></span><br />
<input type="button" id="btnNext" value="next page" />
<script type="text/javascript">
  var cur, btnN;
  function init() {
    cur = document.getElementById("current");
    btnN = document.getElementById("btnNext");
    /* ... */
    // Handle page load and reload
    loadState();
    // Listen for history navigations (e.g. the back button)
    window.addEventListener("popstate", loadState, false);
    window.addEventListener("click", callPushState, false);
  }
  function loadState() {
    // Grab the data for the current state so we can restore it
    var state = history.state;
    if (state != null) {
      cur.innerHTML = state;
    }
    else {
      var hashData = location.hash;
      if (hashData == "") {
        var now = new Date();
        cur.innerHTML = now.toTimeString();
      }
      else {
        var tempHash = hashData.substr(1).split("=")[1];
        cur.innerHTML = unescape(tempHash);
      }
    }
  }
  function callPushState(event) {
    var state = cur.innerHTML;  
    cur.innerHTML = (new Date()).toTimeString();
    varurl = "#time=" + escape(state);
    history.pushState(state, null, url);
  }
  init();
</script>

You should note two items regarding HTML History and this example in particular:

  • Do not save too much state in the History object; save the minimum amount of data possible. Also, the HTML5 History object does not save information by default in the URL, which is good. You don’t want to save too much state there. For example, if saving a search form is important, saving the values of the search is a better option than saving the search results. Be efficient and a good citizen whenever possible.
  • In this example, the state is saved in the URL. This has advantages because it allows a user to share the URL with others, but it also has downsides:
    • The data is not stored securely. This example stores the data in a fairly readable form.
    • The data is limited by the size of the URL in the browser.

Note: In the sample code you can download for this article, you may have noticed a library or an object named Modernizr. Modernizr is a JavaScript library used to test a browser for its ability to perform certain pieces of functionality. You’ll find a link to an MSDN Magazine article on Modernizr in the references.

Wrapping Up

In this article, I introduced you to the HTML5 <video> tag and the History object. Thanks to the great support for HTML5 features in Internet Explorer 10, Windows 8, Windows RT, and Windows Phone, developers have the opportunity to build some really fantastic apps. I hope that you find this article helpful.

References

About the Author

Wallace McClure is a redneck from Tennessee who somehow found his way to Atlanta and Georgia Tech. He was lucky enough to graduate from there twice, with a BS and MS in electrical engineering. He’s always loved things that were new and different, which led to his love of writing software (starting in COBOL and x86 asm), digging into Microsoft's Web technologies, jumping whole-hog into the .NET Framework 1.0 beta, falling in love with mobile way back in 1999, and taking on a whole host of things he probably shouldn't have done but did anyway. Somewhere along the way, he was contacted by someone representing a publisher that would eventually get purchased by John Wiley and Sons and folded into their Wrox division. Several books later, he’s run the gamut from software architecture, to scaling applications, ADO.NET, SQL Server, Oracle, Web, AJAX and mobile technologies. He’s worked for startup companies and many different organizations, all the way up through U.S. federal government agencies.

When not writing software, writing about software, talking about software or thinking he is a comedian, Wally can be found playing golf, in the gym, or coaching basketball.

Find Wally on:

Many thanks to my friends Kevin Darty ( @kdarty) and Stephen Long ( @long2know) for reading through this article and providing some technology suggestions.

MSDN Magazine Blog

MSDN Magazine Right Rail

14 Top Features of Visual Basic 14: The Q&A
Leading off the feature in the January issue of MSDN Magazine is Lucian Wischik’s fantastic look at Visual Basic .NET 14. As Wischik writes, the newes... More...
Wednesday, Jan 7
Big Start to the New Year at MSDN Magazine
Folks, things are hopping over here at MSDN Magazine. We are kicking off the new year with a pair of issues: Our regularly scheduled January issue and... More...
Friday, Jan 2

More MSDN Magazine Blog entries >


Receive the MSDN Flash e-mail newsletter every other week, with news and information personalized to your interests and areas of focus.