Custom player templates are available only for Brightcove Pro and Enterprise customers. If you are interested in upgrading your Brightcove account, please contact Brightcove for more information.
Brightcove player templates enable you to create your own custom components. Custom components can be visual components, like a sidebar listing popular videos or a banner displaying a promotion, or non-visual components, like an analytics SWF.
The main steps in developing and deploying a custom player component are:
<SWFLoader> or <Module> element.This topic includes the following sections:
A custom component is created as a Flash file that you compile into a SWF. You can develop a custom component using ActionScript 3 and the Brightcove Player API. Note that an ActionScript 2 SWF will not be able to interact with the player.
There are two tags available through BEML that allow you to specify SWFs to be loaded by the Brightcove player. The first, SWFLoader, is an element that is added to the display list and positioned by the player, loading your SWF as a child. The second, Module, specifies a SWF that is not added to the display list, but is a non-rendering element that can be used to add logic to the player, such as calling a custom analytics server, providing different logic for rendition selection, etc. In both cases, how you set up your SWF for interaction with the Brightcove Player ActionScript API is the same. Let's look at the recommended code you should use when starting development of your application.
When interacting directly with the Brightcove player, you do not have access to the internal classes to compile against. Because of this, the code you write will have to cast all the API classes to Object instances. This prevents any useful strong typing, code hinting or compile-time checking that an IDE like Flex Builder offers. To get around this limitation, you can use special classes to wrap the internal player classes.
setInterface() method defined if you wish to gain access to the API (which might not always be required by a SWFLoader that doesn't interact directly with the player). The object that is passed to the method implements flash.events.IEventDispatcher and can be wrapped in the com.brightcove.api.BrightcoveModuleWrapper class in order to get strong typing and code hints.
// be sure to import com.brightcove.api.BrightcoveModuleWrapper
private var _player:BrightcoveModuleWrapper;
public function setInterface(player:IEventDispatcher):void {
_player = new BrightcoveModuleWrapper(player);
}
ExperienceModule in the player is available. If it is not, it means that the API was not enabled for the player instance and so the required API classes were not loaded. You can force the loading of these classes through a call to loadModules(), listening for when MODULES_LOADED gets dispatched.
// be sure to import com.brightcove.api.APIModules
// be sure to import com.brightcove.api.events.ExperienceEvent
// be sure to import com.brightcove.api.modules.ExperienceModule
private var _player:BrightcoveModuleWrapper;
private var _experienceModule:ExperienceModule;
public function setInterface(player:Object):void {
_player = new BrightcoveModuleWrapper(player);
_experienceModule = _player.getModule(APIModules.EXPERIENCE) as ExperienceModule;
if (_experienceModule == null) {
_player.addEventListener(ExperienceEvent.MODULES_LOADED, onModulesLoaded);
_player.loadModules();
} else {
checkReady();
}
}
onModulesLoaded() handler. This would simply check to see whether the ExperienceModule was present (which it should be, or the handler wouldn't get called) and call the checkReady() method, which I've yet to present.
private function onModulesLoaded(event:ExperienceEvent):void {
_player.removeEventListener(ExperienceEvent.MODULES_LOADED, onModulesLoaded);
_experienceModule = _player.getModule(APIModules.EXPERIENCE) as ExperienceModule;
if (_experienceModule != null) {
checkReady();
}
}
checkReady() method needs to do another important check that should be present in any SWFLoader or Module SWF, and that is that the TEMPLATE_READY event has been fired by the player. The ExperienceModule has a getReady() method you can use to check this. If the player is not ready, you should establish a listener for the TEMPLATE_READY event.
private function checkReady():void {
if (_experienceModule.getReady()) {
initialize();
} else {
_experienceModule.addEventListener(ExperienceEvent.TEMPLATE_READY, onTemplateReady);
}
}
onTemplateReady() handler would simply call the same initialize() method we had in checkReady(), which I will present last.
private function onTemplateReady(event:ExperienceEvent):void {
_experienceModule.removeEventListener(ExperienceEvent.TEMPLATE_READY, onTemplateReady);
initialize();
}
initialize() method. At this point, the player is ready and the API has been loaded. You are free to do all of the API interaction.
private function initialize():void {
// all custom API interaction code
}
package {
import com.brightcove.api.APIModules;
import com.brightcove.api.BrightcoveModuleWrapper;
import com.brightcove.api.events.ExperienceEvent;
import com.brightcove.api.modules.ExperienceModule;
import flash.display.Sprite;
import flash.events.IEventDispatcher;
public class Module extends Sprite {
private var _player:BrightcoveModuleWrapper;
private var _experienceModule:ExperienceModule;
private function initialize():void {
// all custom API interaction code
}
private function checkReady():void {
if (_experienceModule.getReady()) {
initialize();
} else {
_experienceModule.addEventListener(ExperienceEvent.TEMPLATE_READY, onTemplateReady);
}
}
private function onTemplateReady(event:ExperienceEvent):void {
_experienceModule.removeEventListener(ExperienceEvent.TEMPLATE_READY, onTemplateReady);
initialize();
}
private function onModulesLoaded(event:ExperienceEvent):void {
_player.removeEventListener(ExperienceEvent.MODULES_LOADED, onModulesLoaded);
_experienceModule = _player.getModule(APIModules.EXPERIENCE) as ExperienceModule;
if (_experienceModule != null) {
checkReady();
}
}
public function setInterface(player:IEventDispatcher):void {
_player = new BrightcoveModuleWrapper(player);
_experienceModule = _player.getModule(APIModules.EXPERIENCE) as ExperienceModule;
if (_experienceModule == null) {
_player.addEventListener(ExperienceEvent.MODULES_LOADED, onModulesLoaded);
_player.loadModules();
} else {
checkReady();
}
}
}
}
By using this as the initial code for your SWFLoader and Modules SWFs, you can ensure that the API is ready and you can interact freely with the player instance into which your SWF loads. Of course, since this code is recommended and will unlikely change from module to module, the Brightove Player API SWC also provides this code in an abstract class which you can extend. The following section demonstrates how.
The code in the previous section is a simple template for you to work from when developing custom modules. Since the code will most likely remain consistent, the Brightcove API SWC offers an additional class, CustomModule, which you can extend to get this exact functionality. All that is required is that you extend a single method, initialize(). The following steps show how.
CustomModule as opposed to Sprite.
package {
import com.brightcove.api.CustomModule;
public class Module extends CustomModule {
}
}
initialize(), which takes no parameters and returns no value.
package {
import com.brightcove.api.CustomModule;
public class Module extends CustomModule {
override protected function initialize():void {
}
}
}
initialize() method is invoked, you are free to carry out all of your required interaction. You can gain access to the player through the player property, which contains a BrightcoveModuleWrapper instance. The following shows how you might get access to the ExperienceModule.
package {
import com.brightcove.api.APIModules;
import com.brightcove.api.CustomModule;
import com.brightcove.api.modules.ExperienceModule;
public class Module extends CustomModule {
private var _experienceModule:ExperienceModule;
override protected function initialize():void {
_experienceModule = player.getModule(APIModules.EXPERIENCE) as ExperienceModule;
}
}
}
Using CustomModule as the base class for your Module or SWFLoader SWF will help ensure that you always have access to the API and that you do not interact with the player until it is ready. Because it also exposes a player property that is a BrightcoveModuleWrapper instance, you will get code hints and strong typing as you interact.
Let's look at an example of how to create a custom component and use it in a player template. This example includes these files:
thumb_grid.xml)thumb_grid.html)The ThumbGrid custom component uses the Player API to load content and manipulate the video player component. You can download the source code for this component. The ThumbGrid component defines the following functions:
The ThumbGrid player template is very simple; it incorporates two components, a standard VideoPlayer component and the custom ThumbGrid component, loaded using the SWFLoader element. The player template looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Runtime SYSTEM "http://admin.brightcove.com/dtds/beml_rt.dtd">
<Runtime>
<Layout width="526" height="412">
<VideoPlayer id="videoPlayer" x="3" y="3"
width="486" height="406" depth="1"/>
<SWFLoader width="200" height="406" x="492" y="3"
source="https://help.brightcove.com/developer/docs/playerapi/ThumbGrid.swf"
depth="2"/>
</Layout>
</Runtime>
The attributes of the SWFLoader element specify the size and positioning of the ThumbGrid component within the player layout.
The example HTML page that loads the player includes the player publishing code and a JavaScript snippet that passes a playlist to the player:
<script language="JavaScript" type="text/javascript">
function getPlaylistID() {
return 60818943;
}
</script>
For another example of a custom player component, see Custom Component Sample: Social Sharing Widget.
Some custom components may need to be provided with configuration values from the page or the player at runtime. For example, a component may require an id to be supplied so it can properly associate tracking data, or perform real-time lookups for other settings.
One solution to this problem is to leverage Flash's ability to call out to JavaScript. For example, you might have a playlist id specified in the HTML page by JavaScript and retrieve that id in the component's SWF. The JavaScript fragment in the HTML page would look like this:
<script language="JavaScript" type="text/javascript">
function getPlaylistID() {
return 60818943;
}
</script>
In the Flash component, this playlist ID value is retrieved and used to load a playlist through the Player API:
function onTemplateReady(event:Event):void {
var contentModule:Object = mPlayer.getModule("content");
if (contentModule) {
contentModule.addEventListener("playlistLoad", onPlaylistLoad);
contentModule.getPlaylistAsynch(ExternalInterface.call("getPlaylistID"));
}
}
This strategy may not work if you cannot rely upon the use of JavaScript in the page. An alternative strategy is to specify query parameters for the URL to the external SWF in the <SWFLoader> or <Module> declaration. Using standard Flash development practices, you can then access those URL values and the component can dynamically adjust its behavior, using the values in the query parameters. For example:
<Modules> <Module source="http://hostname.com/player/foo.swf?playlistID='1234'&HAlign='left'"/> </Modules>
Note how the ampersand (&) that joins the query parameters is escaped as & – the Module element, like everything in your player template, needs to be valid XML.
Another way to pass a value to a component is by using the data attribute in the Module or SWFLoader BEML element. For example, if you just need to pass a single string to a loaded SWF, you can put the value in a file and reference it in the BEML like this:
<SWFLoader source="http://my.example.com/path/to/swf/A.swf" data="http://my.example.com/content/data.xml" />
In your SWF, create implicit get and set functions for the property data:
public function get data():String {}
public function set data(value:String):void {}
When the player loads your SWF, the data from the file set in the BEML will be passed to the implicit setter function if the function exists.
When a player loads a custom component SWF, the custom component can access the Player API using the loadModules() method. First, use the player's getModule() method to test whether the player has already loaded the Player API, then use loadModules() to load the Player API if needed. For example:
public function setInterface(player:Object):void {
_player = player;
_experienceModule = _player.getModule("experience");
// if experience module is defined, the API for player is enabled
if (_experienceModule) {
checkTemplateReady();
} else {
// if experience module is not defined, the API for player is disabled
// and needs to be loaded
_player.addEventListener(Event.COMPLETE, onModulesLoaded);
_player.loadModules();
}
}
When setInterface() is called and the player is passed, the event listener listens for Event.COMPLETE fired by the player, then invokes loadModules(). This causes the API module SWF to be loaded by the player, allowing access to the Player API.
Note: This technique works only for custom component SWFs loaded into a player, not for wrapper applications, which still need to enable the Player API through the Publishing module.