By David Hassoun
 
By John Crosby
 
Created
8 March 2011
 

Requirements

 
Prerequisite knowledge

You should be familiar with the Flash Platform, building applications in Flash Professional or Flash Builder, using ActionScript 3, and concepts related to playing video using Flash.
 

 
User level

Advanced
 

 
Sample files

This article is the last in a series on developing media players and experiences with Open Source Media Framework (OSMF). It continues from Part 2 and dives into the usage and creation of OSMF plug-ins, whose capabilities open up a huge realm of possibilities of what can be controlled and achieved through custom-built and third-party plug-ins that you can integrate into any OSMF media player. This article provides a hands-on overview of the capabilities and implementation strategies of the OSMF plug-in system.
 
The four walkthroughs show you how to load static plug-ins dynamically at runtime; load dynamic plug-ins at runtime from a SWF file; create and implement a custom, static plug-in; and use the MAST advertising plug-in to manage ad insertions as pre-roll or post-roll content.
 

 
Walkthrough 8: Integrating simple plug-ins

This walkthrough illustrates how to load static plug-ins—class-based plug-ins that are compiled into the application—dynamically at runtime. The plug-in you use in this walkthrough is the Akamai Basic Streaming Plug-in, which is meant to help facilitate connections and streaming from the Akamai network. The sample dynamically references and instantiates the plug-in class via the getDefinitionByName() method in ActionScript 3, which retrieves a class reference for instantiation by a string of the class path. In addition to loading the plug-in, this walkthrough also shows the syntax and use of the plug-in status event listeners, so that as a developer, you may react to success or failure of plug-in loading.
 
 
Objectives
  • Enable loading of plug-ins dynamic through a centralized method: loadPlugin().
  • Load a static (class-based) plug-in.
  • Handle the successful and failed loading of the plug-in.
 
Setup
  1. Open the file WT08_SimplePlugin.as in the {SAMPLES_PROJECT}/src directory.
     
    Note: This file has been provided as a starting point for these walkthroughs.
     
  2. Set the class file as the application file to compile. There are two different ways of doing this, depending on which program you are using to build your application:
     
    Flash Builder: Right-click WT08_SimplePlugin.as and select Set as Default Application from the context menu that appears. This will add the project to the list of compilable applications. A blue dot on the file icon indicates that the file is the default application file.
     
    Flash Professional: Open OSMF_SampleTemplate.fla and save it as WT08_SimplePlugin.fla. Change the document class for the file (in the Properties panel) to WT08_SimplePlugin.
     
 
Loading the plug-in
  1. Find the comment which looks like the following:
     
//NOTE: Class force-loaded to compile into the application.
Note the class reference below the comment. Putting that reference there forces the plug-in class to be compiled into the application.
 
  1. Under the "//Marker 1:" comment, add two event listeners to the mediaFactory: one for the MediaFactoryEvent.PLUGIN_LOAD that is handled by the onPluginLoaded method, and another for the MediaFactoryEvent.PLUGIN_LOAD_ERROR that is handled by the onPluginLoadFailed method:
//Marker 1: Add the listeners for the plugin load call mediaFactory.addEventListener( MediaFactoryEvent.PLUGIN_LOAD, onPluginLoaded ); mediaFactory.addEventListener( MediaFactoryEvent.PLUGIN_LOAD_ERROR, onPluginLoadFailed );
Note: Having a success handler to notify the application when the plug-in has loaded successfully can be imperative to the sequencing of a media player. Often, the plug-in will need to change or add something to the content that should be played, such as a pre-roll advertisement. If the content is already playing before the plug-in has been loaded successfully, then often the chance to interject or modify has been missed.
 
  1. In the initPlayer() method, locate the comment that begins "//Marker 2:".
  2. Call the loadPlugin() method, passing it the static string BASIC_STREAMING_PLUGIN as the only parameter:
//Marker 2: Load the plugin loadPlugin( BASIC_STREAMING_PLUGIN );
  1. Locate the loadPlugin() method.
  2. Find the comment that begins "//Marker 3:".
  3. Since you are using a static plug-in (class-based, not a SWF file), you will create a variable of type Class named pluginInfoClass and set it equal to the result of calling the getDefinitionByName() method, passing it the source parameter:
//Marker 3: Create the plugin resource using a static plugin var pluginInfoClass:Class = getDefinitionByName( source ) as Class;
Note: Using String variables with the full class path and dynamically retrieving a reference to the class via the getDefinitionByName() method is completely optional, and has nothing to do with OSMF specifically. The reason it was done this way for the sample is to illustrate a more realistic real-world scenario in which the plug-ins to be loaded may not be a fixed set, and could be determined by FlashVars or an XML configuration file. This way, all that is needed is the class to be loaded and String variables that reference the plug-ins.
 
  1. Create a MediaResourceBase variable named pluginResource and set it equal to a new PluginInfoResource object. Pass a new pluginInfoClass() object as the only parameter to the constructor:
//Marker 3: Create the plugin resource using a static plugin var pluginInfoClass:Class = getDefinitionByName( source ) as Class; var pluginResource:MediaResourceBase = new PluginInfoResource( new pluginInfoClass() );
  1. Under the "//Marker 4:" comment, call the loadPlugin() method on the mediaFactory object, passing it the pluginResource variable:
//Marker 4: Load the plugin mediaFactory.loadPlugin( pluginResource );
 
Loading the media after the plug-in has loaded
  1. In the onPluginLoaded event handler method, under the "//Marker 5:" comment, call the loadMedia() method:
protected function onPluginLoaded( event:MediaFactoryEvent ):void { trace( "onPluginLoaded()" ); //Marker 5: Load the media loadMedia(); }
  1. In the loadMedia() method, under the "//Marker 6:" comment, note that the path to the media to load points to the STREAM_AUTH variable, which is a URL that contains the authentication key for an Akamai stream. The URL in the STREAM_AUTH variable is a sample of what an Akamai stream with authentication parameters might look like. The plug-in can help streamline authentication through data such as this. Unfortunately, Akamai authentication tokens expire, so this URL may not work. For testing purposes, change the STREAM_AUTH in the URLResource to PROGRESSIVE_SSL.
  2. Save and run the application. The video should load successfully (see Figure 1).
fig01
Figure 1. Media playing after plug-in has loaded
Implementing static-based plug-ins provides the easiest way to extend the functionality of your media player quickly for custom enhancements or third-party integration. The downside of static plug-ins is that you not only need to have access to the plug-in classes, but your plug-in will need to be compiled into your application. This means that if the plug-in needs to be updated, or if you no longer want to use it, you will need to recompile your application each time and deploy it as necessary. The alternate approach to handle this is to load the plug-in at runtime as a SWF file. This is referred to as a dynamic plug-in, and is the focus of the next walkthrough.
 

 
Walkthrough 9: Analytics integration

This walkthrough demonstrates how to load dynamic plug-ins, which are plug-ins that are loaded at runtime in the form of a SWF file. The walkthrough illustrates some of the more difficult aspects of working with dynamic plug-ins, such as the need to test on a web server so that the plug-ins can be loaded appropriately. Unlike static plug-ins, dynamic plug-ins have more complex environmental concerns even though they are easier to distribute and load at runtime, such as the inability to work locally without a web server and the possibility of requiring a crossdomain.xml file if loading the plug-ins from a different web server or domain from where the player is hosted.
 
One way to handle this complexity issue during the development life cycle is to use static, class-based plug-ins for development, as well as when integration testing begins with web server testing, and then switch to loading as a dynamic plug-in.
 
The plug-in used for this walkthrough is a custom-built plug-in from RealEyes Media that enables Google Analytics tracking from an OSMF player. A key aspect of any complex plug-in is configuration during integration. When you work with OSMF plug-ins, configuration is done in general via metadata. This walkthrough demonstrates how to inject custom metadata for a plug-in.
 
 
Objectives
  • Show the proper setup for testing a dynamic plug-in with a web server and Flash Builder.
  • Load a dynamic (SWF) plug-in at runtime for analytics tracking.
  • Apply custom metadata for a plug-in configuration.
  • Verify that tracking data is being sent.
 
Setup
  1. Set the class file as the application file to compile. There are two different ways of doing this, depending on which program you are using to build your application:
     
    Flash Builder: Right-click WT09_AnalyticsIntegration.as and select Set as Default Application from the context menu that appears. This will add the project to the list of compilable applications. A blue dot on the file icon indicates that the file is the default application file.
     
    Flash Professional: Open OSMF_SampleTemplate.fla and save it as WT09_AnalyticsIntegration.fla. Change the document class for the file (in the Properties panel) to WT09_AnalyticsIntegration.
     
  2. Depending on your coding environment, there are two ways to output your SWF file to a web server:
     
    Flash Builder: In the Project Properties (Main menu > Project > Properties), set the output folder to your local web server.
     
    Flash Professional: In the Publish Settings (File > Publish Settings), set the publish directory for your file to a folder on your local web server. Note that you won't be able to do any debugging in Flash for any projects that use dynamic plug-ins.
     
  3. For Flash Builder, also set the Output folder URL to reflect the same directory on your web server. The settings should look like Figure 2.
fig02
Figure 2. Project setup dialog box
  1. Click OK.
  2. Open WT09_AnalyticsIntegration.as in the {SAMPLES_PROJECT}/src directory.
  3. Note: This file has been provided as a starting point for these walkthroughs.
     
 
Loading the plug-in
  1. In the initPlayer() method, locate the comment that begins "//Marker 1:".
  2. Call the loadPlugin() method, passing it the static constant GTRACK_PLUGIN:
//Marker 1: Load the plugin loadPlugin( GTRACK_PLUGIN );
  1. In the loadPlugin() method, under the "//Marker 2:" comment, create a MediaResourceBase variable named pluginResource and set it equal to a new URLResource. Make sure you pass the source argument to the URLResource constructor as the only parameter:
//Marker 2: Create the plug-in resource using a static plug-in var pluginResource:MediaResourceBase = new URLResource( source );
  1. Open the AnalyticsSampleData.as class in the com/realeyes/data/config/ directory. The only thing in the class is an XML property that provides the configuration data to the plug-in.
  2. The GTrackPlugin analytics plug-in supports tracking to multiple accounts at the same time, percent- and time-based tracking, and the tracking of any of the MediaElement's possible traits, such as playStateChange, volumeChange, and more. The XML in this class has a configuration example of all of the available tracking items that are provided. In this example, you will use percent-based tracking and set up page tracking so you can see when a video was watched as well as how much of that video was watched. For additional configuration information, see the REOPS Google Code page.
  3. Create a Google Analytics account, if you don't already have one.
  4. Under the "//Marker 4:" comment, replace the account text value with your Google Analytics account ID ("Web property ID"). Your ID should be similar to "UA-1782464-4":
<!-- //Marker 4: Set your analytics account ID --> <account><![CDATA[UA-1782464-4]]></account>
  1. Under the "//Marker 5:" comment, set the <url> node's text value to the URL you set up with your Google Analytics account:
<!-- //Marker 5: Set the url that you registered with your GA account --> <url><![CDATA[http://osmf.realeyes.com]]></url>
  1. Under the "//Marker 6:" comment, an initial configuration for percent-based tracking has been provided. This configuration will track the start of the video as well as its progress at 25, 50, and 75 percent (there is no 100 percent marker):
<!-- //Marker 6: Set up the percent based tracking --> <event name="percentWatched" category="video" action="percentWatched"> <marker percent="0" label="start" /> <marker percent="25" label="view" /> <marker percent="50" label="view" /> <marker percent="75" label="view" /> </event>
  1. To track the completion of the video, use the MediaElement's complete event. Under the "//Marker 7:" comment, the complete event tracking configuration has been provided. The name attribute tells the plug-in that you will be tracking the complete event. The category, action, and value attributes map to the Google Analytics tracking values as described in the Google Analytics Event Tracking Guide:
<!-- //Marker 7: Set up the event tracking for the completed event --> <event name="complete" category="video" action="complete" label="trackingTesting" value="1" />
  1. Now that the configuration is set up, you can add the tracking plug-in configuration XML as metadata to the pluginResource object by calling the addMetadataValue() method on the pluginResource object back in the WT09_AnalyticsIntegration.as file. The first parameter should be GTRACK_NAMESPACE and the second should be the static gTrackPluginConfigXML property on the AnalyticsSampleData object:
//Marker 3: Add the metadata necessary to configure the plugin. pluginResource.addMetadataValue( GTRACK_NAMESPACE, AnalyticsSampleData.gTrackPluginConfigXML );
  1. Save and run the application. If you are using Flash Builder, the video should play successfully. If you are using Flash Professional, you will need to load the SWF file in a web browser using a web address to see it run (for example, http://localhost/osmf_samples/). Use a tool such as Firebug to see the tracking calls as they are sent to your Google Analytics account (see Figure 3).
     
    Note: It can take up to 24 hours for the actual tracking data to show up in your Google Analytics dashboard.
     
fig03
Figure 3. Running application in browser with Firebug
  1. Return to the AnalyticsSampleData.as file.
  2. Under the "//Marker 8:" comment, there is an <event ⁄> node with the name of pageView. If this node exists, page view tracking will be sent to Google Analytics:
<!-- //Marker 8: Set up the event tracking for the completed event --> <event name="pageView" />
  1. By default, the URL of the MediaResource will be sent as the "page" so you can identify the videos. To specify a value that will be sent, you add metadata specifying the value to send to the MediaResource object. If you run the application now and inspect the tracking data that is sent you, you should find that a URL that matches the constant PROGRESSIVE_PATH is being sent for the page view tracking (see Figure 4).
fig04
Figure 4. Inspecting the tracking data
  1. In the loadMedia() method, under the "//Marker 9:" comment, call the addMetadataValue() method on the resource object.
  2. Pass GTRACK_NAMESPACE as the first parameter.
  3. For the second parameter, create an object literal with one property named pageURL and set the value to the string "AnalyticsTestVideo":
// Marker 9: Add the metadata to track a "page" view for the video resource.addMetadataValue( GTRACK_NAMESPACE, {pageURL:"AnalyticsTestVideo"} );
  1. Save and run the application. One of the first tracking values set is the page tracking, and you should now see the string "AnalyticsTestVideo" instead of the media's URL (see Figure 5).
fig05
Figure 5. HTTP request parameters
Understanding how you can implement (dynamic and static) plug-ins is the first step toward truly enhancing OSMF-based players. Now you can take plug-ins from the OSMF site or the OSMF marketplace, and start implementing them into OSMF players, including the Strobe Media Playback application. Once you understand how to implement plug-ins, the next step is building them and understanding the guts of a plug-in. The next walkthrough gets you started building a simple plug-in.
 

 
Walkthrough 10: Custom plug-in development

This walkthrough provides some critical knowledge and steps for creating custom plug-ins. It covers creating and implementing a custom, static plug-in that will apply a watermark, or "bug," as a parallel element to all media being displayed and managed via the OSMF player.
 
The key class in creating an OSMF plug-in is the PluginInfo class, which is the main class that interfaces with the OSMF components. The PluginInfo tells OSMF what the plug-in can do and provides the foundation, or base location, of where to start adding custom functionality.
 
The other key aspect of plug-in development with OSMF is understanding the types of plug-ins that can be built and the reasons for using each. There are two plug-in types: proxy and reference:
 
  • Proxy plug-ins return a ProxyElement that will be used to proxy another created MediaElement. Proxy plug-ins can noninvasively alter the behavior of the created MediaElement—for example, blocking the pause feature without changing the player application itself.
  • Reference plug-ins depend on obtaining a reference to one or more MediaElements created by the MediaFactory—for example, a reference plug-in that adds an image overlay that, when clicked, pauses the media playing.
In this walkthrough you will build a proxy plug-in. The proxiedElement property references the MediaElement of the content that was originally created in the OSMF player via the MediaFactory prior to the plug-in being involved. When a MediaElement is created via the MediaFactory, the proxiedElement property is set on any proxy plug-ins that can handle that resource. Usually the proxy plug-in generates a new MediaElement that the plug-in will work with.
 
The idea with plug-ins is that in the PluginInfo constructor, the list of supported MediaFactoryItems and the method to call once the element has been completed should be passed to the super class. That list of MediaFactoryItems is then used by the MediaFactory in the main player to asses whether or not the plug-in needs to handle any of the media elements that are being generated. Each MediaFactoryItem defines what type of content it is able to handle, as well as a method pointer to generate the appropriate MediaElement. After the MediaFactory has generated the proper element for the content that the player is attempting to play, the MediaFactory references the list of MediaFactoryItems from the loaded plug-in. If a match is found, the appropriate media element creation function in the plug-in is called. Once that custom function returns a MediaElement, the proxiedElement property is set on the new plug-in generated MediaElement. The proxiedElement is the original MediaElement generated by the MediaFactory and can then be modified by the plug-in. The possibly modified or custom MediaElement from the plug-in is what eventually gets passed along to be displayed and controlled via the OSMF player.
 
This walkthrough uses the above sequence and the setting of the proxiedElement property to intercept the original MediaElement that is to be played and instead passes along a ParallelElement with a watermark.
 
Note: The ID used for the MediaFactoryItem impacts the priority of which MediaFactoryItem is used to generate the appropriate MediaElement if more than one MediaFactoryItem matches the criteria to generate the element. Any ID that doesn't include "org.osmf" will be given priority. This is valuable, as MediaFactoryItems are added dynamically and may duplicate generic ones within the MediaFactory. Thus this gives priority to the custom MediaFactoryItems.
 
Creating a custom SWF file–based dynamic plug-in is not covered in this walkthrough. However, to generate a dynamic plug-in, all you need to do is create a new custom class that extends MovieClip. Within that custom class, implement a getter method for the property pluginInfo() and return an instance of your custom PluginInfo class. After you compile the custom Sprite class, you'll have your dynamic plug-in.
 
 
Objectives
  • Understand the building blocks of a custom plug-in:
    • PluginInfoResouce
    • PluginInfo object
    • Creating and managing a ProxyElement
  • Build a custom plug-in that does the following:
    • Applies a watermark/bug to all media being displayed—positioned appropriately.
    • Integrates ActionScript 3 traces and ExternalInterface-based JavaScript communication for info and debug info during playback.
  • Load and test the custom plug-in as a static plug-in.
 
Setup
  1. Open the file WT10_CustomPluginDevelopment.as in the {SAMPLES_PROJECT}/src directory.
  2. Set the class file as the application file to compile. There are two different ways of doing this, depending on which program you are using to build your application:
     
    Flash Builder: Right-click WT10_CustomPluginDevelopment.as and select Set as Default Application from the context menu that appears. This will add the project to the list of compilable applications. A blue dot on the file icon indicates that the file is the default application file.
     
    Flash Professional: Open OSMF_SampleTemplate.fla and save it as WT10_CustomPluginDevelopment.fla. Change the document class for the file (in the Properties panel) to WT10_CustomPluginDevelopment.
     
  3. Open CustomSamplePluginInfo.as in the {SAMPLES_PROJECT}/com/realeyes/plugins/custom/ directory.
  4. Open CustomSampleElement.as in the {SAMPLES_PROJECT}/com/realeyes/plugins/custom/element/ directory.
Note: These files have been provided as a starting point for these walkthroughs.
 
 
Loading the plug-in
  1. In WT10_CustomPluginDevelopment.as, in the default package, locate the comment that begins "//Marker 1:".
  2. Create a new PluginInfoResource variable named pluginResource.
  3. Pass a new CustomSamplePluginInfo object as the only parameter to the constructor:
//Marker 1: Create the plugin resource using a static plugin var pluginResource:MediaResourceBase = new PluginInfoResource( new CustomSamplePluginInfo() );
 
Building the PluginInfo object
  1. Open the CustomSamplePluginInfo class in the {SAMPLES_PROJECT}/com/realeyes/plugins/custom/ directory.
  2. Under the "//Marker 2:" comment in the constructor, create a Vector variable named items. The Vector type should be MediaFactoryItem. Set it equal to a new MediaFactoryItem Vector:
//Marker 2: Specify the media items that this plugin will handle var items:Vector.<MediaFactoryItem> = new Vector.<MediaFactoryItem>();
  1. Under the comment "//Marker 3:", create a NetLoader variable named loader and set it equal to a new NetLoader:
//Marker 3: Let the MediaFactory know what kinda of media the plugin can handle... var loader:NetLoader = new NetLoader();
  1. Create a new MediaFactoryItem variable named item. Set item equal to a new MediaFactoryItem object. The first constructor parameter should be the string "com.realeyes.plugins.custom.sample". The second parameter is the canHandleResource on the loader object. The third parameter is the function createMediaElement. The fourth and final parameter is MediaFactoryItemType.PROXY:
//Marker 3: Let the MediaFactory know what kinda of media the plugin can handle... var loader:NetLoader = new NetLoader(); var item:MediaFactoryItem = new MediaFactoryItem( "com.realeyes.plugins.custom.sample", loader.canHandleResource, createMediaElement, MediaFactoryItemType.PROXY );
Note: This MediaFactoryItem can handle anything a NetLoader can handle and calls the createMediaElement method of the CustomSamplePluginInfo class. Once it returns the MediaElement, it sets the proxiedElement property to the original MediaElement generated by the MediaFactory in the player.
 
  1. Add the item to the items array by calling the push() method, passing it the item MediaFactoryItem:
//Marker 3: Let the MediaFactory know what kinda of media the plugin can handle... var loader:NetLoader = new NetLoader(); var item:MediaFactoryItem = new MediaFactoryItem( "com.realeyes.plugins.custom.sample", loader.canHandleResource, createMediaElement, MediaFactoryItemType.PROXY ); items.push( item );
  1. In the createMediaElement() method, under the "//Marker 4:" comment, return a new CustomSampleElement:
//Marker 4: Create a new CustomSampleElement return new CustomSampleElement();
 
Building the ProxyElement
  1. Open CustomSampleElement.as in the {SAMPLES_PROJECT}/com/realeyes/plugins/custom/element/ directory. Note that the constructor doesn't do anything other than pass the proxiedElement parameter to the super class. At this point in your plug-in, the proxiedElement has not been set and the parameter of the constructor is null. The setter of the proxiedElement is what really does all the work and sets up the MediaElement you want to use, since it will not be called or set until after the class has been instantiated.
  2. In the setter for the proxiedElement property, under the "//Marker 5:" comment, create an ImageElement variable named image.
  3. Set image equal to a new ImageElement, passing a new URLResource as the only parameter to the constructor, using the string "assets/osmf_stacked.png":
//Marker 5: Create the image element var image:ImageElement = new ImageElement( new URLResource( "assets/osmf_stacked.png" ) );
  1. Create a new LayoutMetadata variable named layout and set it equal to a new LayoutMetadata object.
  2. Set the following properties and values on the layout object:
     
    • width: 75
    • height: 66
    • bottom: 0
    • right: 0
//Marker 5: Create the image element var image:ImageElement = new ImageElement( new URLResource( "assets/osmf_stacked.png" ) ); var layout:LayoutMetadata = new LayoutMetadata(); layout.width = 75; layout.height = 66; layout.bottom = 0; layout.right = 0;
  1. Add the layout LayoutMetadata to the image ItemElement:
//Marker 5: Create the image element var image:ImageElement = new ImageElement( new URLResource( "assets/osmf_stacked.png" ) ); var layout:LayoutMetadata = new LayoutMetadata(); layout.width = 75; layout.height = 66; layout.bottom = 0; layout.right = 0; image.addMetadata( LayoutMetadata.LAYOUT_NAMESPACE, layout );
  1. Under the "//Marker 6:" comment, create a new ParallelElement named parallel:
//Marker 6: create a parallel element so we can add the image & original element var parallel:ParallelElement = new ParallelElement();
  1. Under "//Marker 7:", add value and image as children of the parallel element:
//Marker 7: Add the proxied element and the image as children parallel.addChild( value ); parallel.addChild( image );
  1. Under the "//Marker 8:" comment, set the super.proxiedElement equal to the parallel element:
//Marker 8: Set the proxied element super.proxiedElement = parallel;
  1. Save and run the application. The video should play and the OSMF logo will appear on top of the video in the lower-right corner (see Figure 6).
fig06
Figure 6. Application running with custom watermark plug-in
  1. Return to the CustomSampleElement class. Under the "//Marker 9:" comment, add an event listener for the MediaElementTrait.TRAIT_ADD event and set the event handler method to be _onAddTrait():
//Marker 9: Add trait add and remove listeners proxiedElement.addEventListener( MediaElementEvent.TRAIT_ADD, _onAddTrait );
  1. Add an event listener for MediaElementEvent.TRAIT_REMOVE to be handled by the _onRemoveTrait() method:
//Marker 9: Add trait add and remove listeners proxiedElement.addEventListener( MediaElementEvent.TRAIT_ADD, _onAddTrait ); proxiedElement.addEventListener( MediaElementEvent.TRAIT_REMOVE, _onRemoveTrait );
  1. The _onRemoveTrait() event handler method traces out the trait type that is being removed.
In the _onAddTrait() event handler method, you need to evaluate which trait is being added and react to that trait. In this method, a switch statement has been created that evaluates and traces the traitType property of the MediaElementEvent:
 
  1. Under the "//Marker 10:" comment, create a new TimeTrait variable named timeTrait.
  2. Set timeTrait equal to the result of calling the getTrait() method on the proxiedElement. Pass the trait type of MediaTraitType.TIME to the getTrait() method as the only parameter, making sure to cast the result as a TimeTrait object:
//Marker 10: Get the time trait, so we can handle the duration changed event var timeTrait:TimeTrait = proxiedElement.getTrait( MediaTraitType.TIME ) as TimeTrait;
  1. Add an event listener to the timeTrait object for the TimeTrait.DURATION_CHANGE event. Handle this event with the _onDurationChanged() method. The _onDurationChanged() method traces the value of the changed duration to the debugger:
//Marker 10: Get the time trait, so we can handle the duration changed event var timeTrait:TimeTrait = proxiedElement.getTrait( MediaTraitType.TIME ) as TimeTrait; timeTrait.addEventListener( TimeEvent.DURATION_CHANGE, _onDurationChanged );
  1. Save all of the files and run the application in debug mode. You should see debugger output similar to that shown in Figure 7. The output to note would be the "New Duration:". This is what is being output when the event handler for TimeEvent.DURATION_CHANGE is executed.
fig07
Figure 7. Debugging the application
Being able to create your own plug-ins that affects the visual display or monitors the state of the media application only scratches the surface of what you can do. The next walkthrough focuses on integrating advertising into your application with the use of MAST, one of the industry standards, and the MAST Advertising plug-in.
 

 
Walkthrough 11: Advertising integration

This walkthrough shows how to use the MAST advertising plug-in to manage ad insertion as pre-roll or post-roll content. The key aspects of this walkthrough are the simplicity of integration and the control that can be achieved by using the industry-standard MAST (or VAST) data format with external XML-driven content, and linking that data with OSMF and metadata.
 
Note: Media Abstract Sequencing Template (MAST) is "an XML-based declarative language to define a set of triggers and conditions to specify sequencing and layout of advertising for a video player." You can find out more about the Akamai-based MAST specification at the MAST SourceForge project (PDF, 161 KB).
 
The process is the same as the other samples when it comes to loading a plug-in, but in this case you simply apply the MAST metadata to the media resource and OSMF does the rest.
 
Caution: This sample may have an issue if the compiler variable CONFIG::LOGGING is set to true. It appears to throw an error in the MASTConditionManager (line 291) when trying to use the logger that is null at that point.
 
 
Objectives
  • Load the static MAST plug-in at runtime.
  • Once the plug-in is loaded, apply the MAST metadata to the media resource.
  • Understand the basic pieces and format of a MAST sample.
  • Be able to change from a pre-roll to a post-roll by utilizing the MAST data.
 
Setup
  1. Open WT11_CustomAdverts.as in the {SAMPLES_PROJECT}/src directory.
     
    Note: These files have been provided as a starting point for these walkthroughs.
     
  2. Set the class file as the application file to compile. There are two different ways of doing this, depending on which program you are using to build your application:
     
    Flash Builder: Right-click WT11_CustomAdverts.as and select Set as Default Application from the context menu that appears. This will add the project to the list of compilable applications. A blue dot on the file icon indicates that the file is the default application file.
     
    Flash Professional: Open OSMF_SampleTemplate.fla and save it as WT11_CustomAdverts.fla. Change the document class for the file (in the Properties panel) to WT11_CustomAdverts.
     
 
Specifying advertisements with VAST/MAST
  1. Under the "//Marker 1:" comment in the initPlayer() method, call the loadPlugin() method and pass it the MAST_PLUGIN_INFO_CLASS string constant:
//Marker 1: Load the plugin loadPlugin( MAST_PLUGIN_INFOCLASS );
  1. Open the mast_sample_onitemstart.xml file in the {SAMPLES_PROJECT}/assets/mast/ directory. This is a MAST file that defines simple advertising for the player.
  2. The mast_sample_onitemstart.xml file defines three main things:
     
    • Trigger: "preroll"
    • Condition: "OnItemStart"
    • Source: advertising media
  3. This defines a short video clip that plays before you see the original media that you clicked the player to play. After you review the MAST file, close it.
     
  1. In the loadMedia() method, under the "//Marker 2:" comment, create a new Metadata object named metadata:
//Marker 2: Assign to the resource the metadata that indicates... var metadata:Metadata = new Metadata();
  1. Call the addValue() method on the metadata object, passing MASTPluginInfo.MAST_METADATA_KEY_URI as the first parameter and the static constant string MAST_URL_PREROLL as the second parameter:
//Marker 2: Assign to the resource the metadata that indicates... var metadata:Metadata = new Metadata(); metadata.addValue( MASTPluginInfo.MAST_METADATA_KEY_URI, MAST_URL_PREROLL );
  1. Add the metadata to the resource by calling the addMetadataValue() method on the resource object, passing it MASTPlugininfo.MAST_METADATA_NAMESPACE as the first parameter and the metadata object as the second parameter:
//Marker 2: Assign to the resource the metadata that indicates... var metadata:Metadata = new Metadata(); metadata.addValue( MASTPluginInfo.MAST_METADATA_KEY_URI, MAST_URL_PREROLL ); resource.addMetadataValue( MASTPluginInfo.MAST_METADATA_NAMESPACE, metadata );
  1. Save and run the application. A short video ad will appear before the specified video plays (see Figures 8–9).
fig08
Figure 8. Advertisement pre-roll
fig09
Figure 9. Main video playback
  1. Change the second parameter of the addValue() method call from MAST_URL_PREROLL to MAST_URL_POSTROLL. This changes the MAST file from mast_sample_onitemstart.xml to mast_sample_onitemend.xml.
  2. If you open and review mast_sample_onitemend.xml, it defines the same data, trigger, condition, and source, and specifies a video ad that will play after the original media has played.
  3. Save and run the application. The video ad should play after the original media (see Figures 10–11).
fig10
Figure 10. Original video
fig11
Figure 11. Video post-roll

 
Where to go from here

You should now have a greater understanding of plug-ins—how to use them, how to create them, and what you can do with them. Mastering the capabilities of layout controls, using the full spectrum support of media formats and delivery, and exploiting the extensibility layer of plug-ins will provide you with an arsenal to make industry-leading, OSMF-driven applications.
 
Although OSMF is in its infancy, it already provides a powerful and robust framework for media experiences. Check out a number of other OSMF articles on the Adobe Developer Connection, including one on live multicast streaming using OSMF.
 
Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License+Adobe Commercial Rights
 
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.