Popcorn JS Tutorial

May 17, 2014, 6:40 pm
Author: James Griffiths

Mozilla's Popcorn JS library allows developers to bring richer functionality to HTML 5 video. In the following tutorial we're going to take you through developing a single page web app with Popcorn JS.

This is what we're looking to create:

First, you'll need to download the following libraries:

Include the necessary CSS and JS files from these libraries into a basic HTML page like so:

<!DOCTYPE html>
<html>
  <head> 
    <meta charset="utf-8">
    <!-- Include necessary CSS files for libraries -->
    <link rel="stylesheet" href="bootstrap.min.css">
    <link rel="stylesheet" href="ui-lightness/jquery-ui-1.10.4.custom.min.js">
  </head>
  <body>
    <!-- Include necessary JS files at bottom of web page before closing body tag -->
    <script src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
    <script src="jquery-1.10.2.js"></script>
    <script src="bootstrap.min.js"></script>
    <script src="jquery-ui-1.10.4.custom.min.js"></script>
    <script src="popcorn-1.5.6.min.js"></script>
  </body>
</html>

Now that we've established a bare bones HTML page that includes all the necessary third-party libraries we can start to implement the mark-up for structuring our Popcorn video App. As we're using the Twitter Bootstrap library to help style the mark-up we'll adopt the classes used from there for general layout only to add our own custom CSS styles for more specific styling needs later on if we need to.

First of all we make our App mobile friendly and force IE to use the latest rendering engine, by adding the following to the <head> of our web page:

  • <meta http-equiv="X-UA-Compatible" content="IE=edge">
  • <meta name="viewport" content="width=device-width, initial-scale=1">
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Include necessary CSS files for libraries -->
    <link rel="stylesheet" href="bootstrap.min.css">
    <link rel="stylesheet" href="ui-lightness/jquery-ui-1.10.4.custom.min.css"> 
  <head>

Developing from this we can now start to map in the necessary mark-up for laying out the page and including our video. Place the following HTML snippet between the <body></body> tags of your basic web page:

<div class="container">
  <div class="row">
	<div class="col-xs-12 col-sm-6 col-md-6">
	  <video id="video-player" poster="_assets/_images/skateboarding-video-1.jpg">
		<source src="_assets/_video/Skateboarding-09-09-2012.mp4" type="video/mp4">	
		<source src="_assets/_video/Skateboarding-09-09-2012.webm" type="video/webm">	
		<source src="_assets/_video/Skateboarding-09-09-2012.ogv" type="video/ogg">	
	  </video>
    </div>


    <div class="col-xs-12 col-sm-6 col-md-6">
	  <div class="panel panel-default">
		<div class="panel-heading">
		  <h3 class="panel-title">Wikipedia entry</h3>
		</div>

		<div class="panel-body">
		  <div id="wiki"></div>
		</div>
	  </div>


	  <div class="panel panel-default">
		<div class="panel-heading">
		  <h3 class="panel-title">Locations</h3>
		</div>
 		<div class="panel-body">
   		  <div id="map"></div>
	    </div>
	</div>
    </div>
  </div>
</div>

In the above we have defined some wrappers for our page, using bootstrap 3 specific classes to implement layout and basic styling, and included the HTML5 video tag with references to the video files we want to use as well as using a poster image to represent our video and set up some panels to display a wikipedia entry and a Google Map.

We'll configure these a little later during the tutorial but for now change the video/image file names and path references to your own, load the page in your browser and you should see something like the following being displayed:

Okay, very basic and nothing particularly fancy. We've deliberately disabled the default HTML5 video controls as we are going to implement our own playback functionality through methods offered by Popcorn JS.

Underneath the closing video tag add the following snippet of HTML:

<form class="form-horizontal" id="form-controls">
    <div class="form-group">
      <div class="col-xs-12 col-sm-12 col-md-12" id="percentage-played"></div>
      <div class="col-xs-6 col-sm-4 col-md-4">
	<div class="btn-group btn-group-md">
          <button type="button" class="btn btn-default" id="pause">
	    <img src="_assets/_images/pause.png">
	  </button>


          <button type="button" class="btn btn-default" id="play">
	    <img src="_assets/_images/play.png">
	  </button>


	  <button type="button" class="btn btn-default" id="loop">
	    <img src="_assets/_images/loop.png">
	  </button>

	</div>
      </div>


      <div class="col-xs-6 col-sm-8 col-md-8">
	<div id="slider" class="form-control"></div>
      </div>
    </div>
  </form>

Again, nothing terribly complicated with the above mark-up, just a case of setting the scene for where we want to take our video App.

Scripting the App

Below the last script block at the bottom of our web page add the following JavaScript code (we could put this into a separate file but this is something you can do yourself if you wish to):

<script>
    $(document).ready(function(){

      // Initialise variables
      var map,
          popcorn,
          loopVideo = false;

      // Initialise Popcorn
      function initiatePopcorn(){
	popcorn = Popcorn('#video-player', { frameAnimation: true });
        
        // Define volume slider functionality
	var slider = $("#slider").slider({
	    min: 0,
	    max: 10,
	    step: 1,
	    range:10,
	    value:5,
	    slide: function( event, ui ) {
	      popcorn.volume((ui.value/100 * 10)); // We need to set this as a float because popcorn audio is between 0 and 1 - (i.e. 0.5)  :)
	    }
	});

	// How long does the video last?
	popcorn.on("loadeddata", function(event){
	  $('#percentage-played').html('Video is ' + Math.round(popcorn.duration()) + ' seconds in length');
	});

	// Initially set volume
	popcorn.volume(0.5);
      }
    });
  </script>

To start with we include our code within jQuery's document ready function so we can be sure that our DOM is loaded and ready to be used.

Developing from this we then declare global variables at the top of our script which we will use later on and then create a function called initiatePopcorn which will contains the necessary functionality that performs all of the heavy lifting for our App.

Within this function we create a Popcorn object and tell it which video element to target. We also pass in a frameAnimation property, setting it to true, as one of the object constructor options - this allows the requestAnimationFrame loop to be used by those browsers which support this.

Following from this we then configure our jQuery UI slider element with the necessary variables to help manipulate volume playback for our App. Within this configuration we declare the retrieved slide value which is fed to the volume method of the popcorn object as a float value (I.e. 0.1, 0.2 etc) as we need to manipulate a numeric range between 0 and 1 in order to change the video's playback volume (very important!)

Then we move onto using Popcorn's loadeddata event, which allows us to detect when the video metadata has loaded, so we can feedback to the user the exact duration of the video in seconds.

Finally we set the initial volume for our App at 50% of the total volume (remember we are using float values to represent this so 50% is represented as 0.5).

Now we need to add the functionality to script our buttons for video playback and control.

At the bottom, but staying inside, of our initiatePopcorn function add the following script elements:

$('#play').on('click', function(){
  popcorn.play();
});

// Pause video
$('#pause').on('click', function(){
  popcorn.pause();
});

// Loop functionality
$('#loop').on('click', function(){
  if(loopVideo === false)
  {
    popcorn.loop(true);
    loopVideo 	= true;
  }
  else {
    popcorn.loop(false);
    loopVideo 	= false;
  }
});

Now we have added the functionality to actually play, pause and loop the video for our App.

If you were to save the file and load the page in your browser however you would find that nothing happens. Why? Well, we need to actually call the initiatePopcorn function in order to see that magic in action!

Add the following function call underneath (and outside of) the initiatePopcorn function declaration:

initiatePopcorn(); 

Save the file and if you now load your page in the browser and test the controls you should see that functionality working.

If not, check that you have entered the above code snippets correctly and that your file paths to the JavaScript and CSS files are correct.

Adding captions to our video

Assuming that all of the above is working successfully you have scripted a basic video player that allows you to perform the following actions:

  • Play
  • Pause
  • Loop
  • Adjust the volume

Popcorn allows us to make our video even more interactive and we'll take advantage of this by adding captions for various breakpoints in our video. In order to do this we first of all need to add some additional HTML mark-up to our page to display our soon to be scripted video captions.

Underneath the form-controls block add the following snippet of HTML:

<div class="panel panel-default">
    <div class="panel-heading">
      <h2 class="panel-title">Caption</h2>
    </div>

    <div class="panel-body">
      <aside id="video-caption"></aside>
    </div>
  </div>

Caption

Now that we have the necessary mark-up available we can start to add captions during video playback. Thanks to the popcorn API this is quite trivial to do with the footnote plugin as demonstrated below. All you need to decide, when working with your own video is what breakpoints to use for the start and end times for each caption, where the caption will be displayed and last, but certainly not least, the text for each caption.

Add the following snippet(highlighted in bold) beneath the declaration to initialise popcorn:

popcorn = Popcorn('#video-player', { frameAnimation: true });
  popcorn.footnote({
	start: 1,
	end: 6,
	target: 'video-caption',
	text: 'Skateboarding footage taken during September 2012 in Stafford town'
  }).footnote({
	start: 6,
	end: 10,
	target: 'video-caption',
	text: '14 years away from the sport.....'
  }).footnote({
	start: 10,
	end: 18,
	target: 'video-caption',
	text: 'Ollie impossible in Stafford town skatepark'
  }).footnote({
	start: 18,
	end: 26,
	target: 'video-caption',
	text: "Curb island kickflip at Sainsbury's car park"
  }).footnote({
	start: 26,
	end: 30,
	target: 'video-caption',
	text: "Switch frontside 180 ollie over curb island at Sainsbury's car park"
  }).footnote({
	start: 30,
	end: 36,
	target: 'video-caption',
	text: "Ollie over fence at Wilkinson's car park"
  }).footnote({
	start: 36,
	target: 'video-caption',
	text: "Point your eyes below and a set of Flickr images are displayed at the end of the video"
  });

As you've probably guessed each footnote represents a particular point in the video that we want to display a caption for along with the duration for that caption (determined by its start and end points, represented in the seconds of the video). One of the nice things about popcorn is that it allows us to chain methods together instead of have to declare new object instances for each method we want to use.

If you save the file, reload the page and play the video you should start to see the captions you have scripted being displayed at the points in the video you declared.

If so, congratulations you can now move onto the next stage which will involve configuring the display of a specific wikipedia page entry to accompany our video App. If not, go back and check the code to ensure you have no bugs that could be breaking or preventing the captions from being displayed.

Adding a touch of Wikipedia to our App

Using the wikipedia plugin for Popcorn we can include an entry from that online encyclopedia into our App. As the topic for this App tutorial involves skateboarding we're going to return an entry from Wikipedia for that very activity.

At the end of the last footnote method and before the semi-colon terminating the chain methods add the following snippet (highlighted in bold):

footnote({
	start: 36,
	target: 'video-caption',
	text: "Point your eyes below and a set of Flickr images are displayed at the end of the video"
  }).wikipedia({
    start:0,
    src: "http://en.wikipedia.org/wiki/Skateboarding",
    title: "Skateboarding",
    target: "wiki",
    numberofwords: 100
  });

The wikipedia plugin uses a number of pre-defined keys that we can declare particular values for:

  • start
  • src
  • title
  • target
  • numberofwords

With these configuration options available you can decide at what point in the video playback that you want the wikipedia plugin to start displaying the article you have declared (in the src key), the title for the wikipedia entry, where it will be displayed and how many words of the article you want displayed (maximum allowable is 200 words).

Save your file, reload the page in your browser and all things being well you should see the specified wikipedia article being displayed at the defined breakpoint in the video during playback.

Getting funky with Google Maps

So far, so good but we can take this a step further and incorporate the Google Maps API into our page so we can start to plot points on our map that correspond to physical locations in our video.

Popcorn does include a Google Maps plugin but, for whatever reasons, we just couldn't get this to work so we opted for manually configuring our own Google Maps functionality instead. If anyone can provide a heads up on why the Google Maps plugin doesn't appear to work we'd be very appreciative - after a considerable amount of time racking our brains trying to use the plug-in we were quite mystified on why it wouldn't do what it was supposed to do!

Place the following code snippet (highlighted in bold) towards the top of the custom script block, above the initiatePopcorn function but below the global variables:

// Initialise variables
  var map,
        popcorn,
        loopVideo = false;

  // Initialise Google Map functionality
  function initialize() {
    var mapCanvas   = document.getElementById('map'),
        mapOptions  = {
	   		center: new google.maps.LatLng(52.8066574, -2.1225527),
	   	        zoom: 16,
	   		mapTypeId: google.maps.MapTypeId.ROADMAP
		      };
	map 	    = new google.maps.Map(mapCanvas, mapOptions);
  };

  // Load Google Maps and intialise
  google.maps.event.addDomListener(window, 'load', initialize);

So we initialise our Google Map, wrapping that within a custom function, supplying the necessary parameters to configure how we want that displayed and which geographical latitude and longitude our map will use.

Finally we use the Google Map API addDomListener handler to call our function on the window load event so that the map will be displayed on the page ready for use by our Popcorn script.

Now we need to create a function that will allow us to tell popcorn to add markers to the Google Map at various points during the playback of the video.

Underneath the Google Map API addDomListener handler add the following code snippet:

// Define Map marker
function mapMarker(lat, lng)
{
  var marker = new google.maps.Marker({
      position: new google.maps.LatLng(lat,lng)
  });

  marker.setMap(map);

};

Our mapMarker function accepts 2 parameters: lat and lng which correspond to the latitude and longitude coordinates of where we want the newly generated marker to be placed on our Google Map.

Now we need to instruct our Popcorn object to interact with the Google Map and place markers at specific points depending on where in the video the user is currently viewing. Thanks to the Code plugin this is a relatively quick and simple task to achieve.

Enter the following code snippet (highlighted in bold) at the end of the last wikipedia method and before the semi-colon terminating the chain methods:

wikipedia({
    start:0,
    src: "http://en.wikipedia.org/wiki/Skateboarding",
    title: "Skateboarding",
    target: "wiki",
    numberofwords: 100
  }).code({
    start: 10,
    end: 17,
    onStart: function(options){
      mapMarker(52.8059991, -2.1219787);
    }
  }).code({
    start: 18,
    end: 25,
    onStart: function(options){
      mapMarker(52.8075767, -2.1238232);
    }
  }).code({
   start: 32,
   end: 35,
   onStart: function(options){
     mapMarker(52.8075767, -2.121275);
   }
 });

We've chained a sequence of code methods that allows our custom Popcorn object to generate and place markers on the Google Map courtesy of our mapMarker function at specific breakpoints in the video playback. Now if you save your changes and reload the web page in your browser you should see those markers starting to populate the Google Map as the video playback increases in duration.

And there you have it! A simple one page App using a collection of modern technologies and resources all brought together through scripting with Mozilla's Popcorn JS library and associated plug-ins.

If you want to see the completed page (with additional features and enhancements) then point your browser this way.

Categories

« Return to Posts

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.