Popcorn.js, the HTML5 <video> framework, is getting a facelift. Rick, Al and I spent last weekend working on Popcorn with Anna and Scott from the Centre for Development of Open Technology (CDOT) at Seneca College on the forthcoming release of Popcorn JS.

The History

Bocoup’s own Nick Cammaratta attended a week long code sprint for Popcorn JS 0.1 leading up to the 2010 Mozilla summit back in July of 2010.

At CDOT, Anna and Scott have been working under David Humphrey and Brett Gaylor on Mozilla’s Web Made Movies project. For the past 5 months Anna and Scott have solved numerous problems dealing with web video. Their popcorn.js 0.1 demo represents enormous thought leadership in HTML5 <video> interaction.

Mozilla recently engaged Bocoup to develop an authoring tool for Popcorn.js to make it even easier for filmmakers to make web movies with Popcorn. The Popcorn team also invited us to recommend a new approach to organizing the popcorn.js code into a framework that includes better code organization and abstraction, a plugin architecture, and smart syntactic sugar for interacting with the <video> element.

Bocoup’s Recommendation

With this in mind we recommended using an enhanced singleton pattern, originally pioneered by the jQuery project. We made this recommendation based on the desire to organize the Popcorn.js 0.1 demos into a more reusable, modular and extensible structure. We also selected method names that will be familiar to developers in the front end community, and generally designed the API in an approachable way.

One of the original goals for popcorn.js 0.1 was to make it easy for filmmakers to use. For this reason XML declaration was selected as the interface for initializing popcorn. Now that Bocoup is developing an authoring tool for filmmakers, we are able to take a step back and produce a more developer friendly JavaScript API.

Imagine being able to write the following code:

popcorn-api-examples.js

Popcorn('#video')
  .subtitle({
    start: 10,
    end: 30,
    text: 'The title of my video'
  })
  .play()

Popcorn('#video2')
  .subtitle({
    start: 10,
    end: 20,
    text: 'The title of my video'
  },
  {
    start: 20,
    end: 30,
    text: 'The producer of my video'
  })
  .play()

By using a factory pattern, we were able to use the <video> object’s native methods and properties to build a set of getter, setter and controller functions to include in every Popcorn object. By normalizing these, the framework allows developers to write chainable functions executions off the returned Popcorn object:

popcorn-api-examples-natives.js

Popcorn('#video')
  .play()
  .currentTime(30)
  .pause()
  .listen('timeupdate', function(event){
    console.log( this ) // the current popcorn object
    this.currentTime() // the currentTime
  })
  .play()
  .currentTime(20)

Popcorn also offers a plugin factory with two signatures. Pattern 1 below lets you manage time updating by your self, where as patterns 2 and 3 offer a structure to manage your video events for you.

popcorn-plugin-patterns.js

// Pattern 1
// Provide a function that returns an object
(function (Popcorn) {
  Popcorn.plugin( "pluginName" , function( options ) {
    // do stuff
    // this refers to the popcorn object

    // You are required to return an object
    // with a start and end property
    return {
      start: function(){...},
      end: function(){...}
    };
  });
})(Popcorn);


// Pattern 2
// Provide an object
// Popcorn will manage the events
(function (Popcorn) {
  Popcorn.plugin( "pluginName" , {
    _setup : function( options ) {
       // setup code, fire on initialization
       // options refers to the options passed into the plugin on init
       // this refers to the popcorn object
    },
    start: function( event, options ){
       // fire on options.start
       // event refers to the event object
       // options refers to the options passed into the plugin on init
       // this refers to the popcorn object
    },
    end: function( event, options ){
       // fire on options.end
       // event refers to the event object
       // options refers to the options passed into the plugin on init
       // this refers to the popcorn object
    }
  });
})(Popcorn);


// Pattern 3
// Provide an object with a plugin wide name space
// Popcorn will manage the events
(function (Popcorn) {
  Popcorn.plugin( "pluginName", (function(){

    // Define plugin wide variables out here

    return {
      _setup : function( options ) {
         // setup code, fire on initialization
         // options refers to the options passed into the plugin on init
         // this refers to the popcorn object
      },
      start: function( event, options ){
         // fire on options.start
         // event refers to the event object
         // options refers to the options passed into the plugin on init
         // this refers to the popcorn object
      },
      end: function( event, options ){
         // fire on options.end
         // event refers to the event object
         // options refers to the options passed into the plugin on init
         // this refers to the popcorn object
      }
  })();
})(Popcorn);

This plugin architecture allows popcorn.js core to focus on wrapping the <video> element and managing events on a timeline, thereby externalizing plugin related functionality like ‘showing a map of a place at a certain time’, or ‘displaying a subtitle at a certain time’.

In addition to taking a solid and fully unit tested stab a this new architecture in the 0.2 branch of Popcorn JS this weekend, we started converting the original Popcorn JS 0.1 commands into Popcorn JS 0.2 plugins. We also identified milestones for the Popcorn JS project, and fully ticketed what needs to be done to release 0.2 on time.

The plan is to release a fully document and unit tested Popcorn JS 0.2 with plugins that offer full coverage of the Popcorn JS 0.1 demos on December 21st. If your are interested in getting involved, please join us in the #popcorn channel on irc.mozilla.org. We would love to work with other developers in the community. For updates, follow @PopcornJS on twitter.