|
|
This is the integration with JW FLV Player v3.16. The integration with JW FLV Player v4 (ActionScript 3) is available here.
Above you see a demo of the Adotube Overstream Platform integrated as a plugin into the popular open source JW FLV Player (version 3.16). The sample offer is configured to be shown from the time the video player is launched to 1/2 of the way into the video.
The source code archive for the above integration is available.
This integration was performed according to the Overstream Platform Plugin Interface Specification for AS2 Players.
You will need the input parameters overstreamPlatformURL (the URL of the OverstreamPlatform.swf) and omlSource (the URL of the plugins' description and timing) in order for the integration to function. For your integration testing, you can use the parameters used for the embed above (by grabbing them from the HTML source of this page). Before your integrated system will go live, you will register as a publisher with Adotube, and the actual live parameters will be provided to you as part of the embed code in the Adotube Publisher Management Console.
The Overstream Platform integration into the JW FLV Player is accomplished via creation of a new View class, com.adotube.JWFLVOverstreamPlatformAdapterView, which is added into the com.jeroenwijering.players.MediaPlayer's setupMCV() method in the standard way:
... var opAdapterView = new com.adotube.JWFLVOverstreamPlatformAdapterView(controller,config,feeder); vws.push(opAdapterView); ...
These two lines of code come after the following line of code:
var vws = new Array(dpv);
The com.adotube.JWFLVOverstreamPlatformAdapterView Class creates an empty container MovieClip on top of the JW FLV Player's display stack and loads OverstreamPlatform.swf into it. Once the OverstreamPlatform.swf is loaded, the JWFLVOverstreamPlatformAdapter sets up the necessary interface between the OverstreamPlatform and the JW FLV Player. The com.adotube.JWFLVOverstreamPlatformAdapterView Class code is listed below. No other modifications were made to the JW FLV Player.
import com.jeroenwijering.players.*;
import mx.utils.Delegate;
/**
*
* @author maxroz@adotube.com
* @version 1.12
*
* Implements Overstream Platform Interface 1.0.
*
**/
class com.adotube.JWFLVOverstreamPlatformAdapterView extends AbstractView {
// params: overstreamPlatformURL, omlSource
var overstreamPlatformURL:String; // OverstreamPlatform.swf source URL
var opContainer:MovieClip; // Reference to the container MovieClip into which OverstreamPlatform.swf is loaded
var opLoaded:Boolean = false; // Is OverstreamPlatform.swf loaded?
// Player-Related Data
var playbackDuration:Number;
var playbackTime:Number;
var playerVolume:Number;
var playerState:String;
function JWFLVOverstreamPlatformAdapterView(ctr:AbstractController,cfg:Object,fed:Object) {
super(ctr,cfg,fed);
overstreamPlatformURL = _root.overstreamPlatformURL;
createOPContainer();
loadOverstreamPlatform();
Stage.addListener(this); // for the fullscreen event
}
/*
* Create the container MovieClip into which the OverstreamPlatform.swf will be loaded.
*/
function createOPContainer() {
var jwClip:MovieClip = config["clip"];
opContainer = jwClip.createEmptyMovieClip("opContainer", jwClip.getNextHighestDepth());
// OverstreamPlatform should at a lower depth than the player controlbar, so we swap them
jwClip.controlbar.swapDepths(opContainer);
}
/*
* Load the OverstreamPlatform.
*/
function loadOverstreamPlatform() {
if (overstreamPlatformURL) {
var mcl:MovieClipLoader = new MovieClipLoader();
mcl.addListener(this);
System.security.allowDomain(overstreamPlatformURL);
mcl.loadClip(overstreamPlatformURL, opContainer);
}
}
//////////// MovieClipLoader Callbacks ////////////////////////
function onLoadInit(opContainer:MovieClip) {
// If omlSource parameter is passed via initialization params for the player,
// pass it to the OverstreamPlatform. (The alternative is to pass it via the query string
// of the the OverstreamPlatform.swf.)
if (_root.omlSource) {
opContainer.omlSource = _root.omlSource;
} else if (_root.oml) {
opContainer.oml = _root.oml;
}
///////////// Enable Player-Plugin Interface.
initializeOverstreamPlatformInterfaceIncoming();
///////////// Layout the OverstreamPlatform in the available space.
op_onLayoutSizeChanged(config["displaywidth"], config["displayheight"]);
//////////// Initialize OverstreamPlatform
op_onPlayerStateChanged(getPlayerState());
if (playerVolume !== undefined) {
op_onPlayerVolumeChanged(playerVolume);
}
// opContainer.onUserScrubbing(false);
if (playbackDuration !== undefined) {
op_onPlaybackDurationAvailable(playbackDuration);
}
}
///////////// Player-Plugin Interface /////////////////
///////////// Incoming Methods ////////////////////////
function initializeOverstreamPlatformInterfaceIncoming() {
opContainer.getPlaybackTime = Delegate.create(this, getPlaybackTime);
opContainer.requestPlayerPlay = Delegate.create(this, requestPlayerPlay);
opContainer.requestPlayerPause = Delegate.create(this, requestPlayerPause);
opContainer.requestPlayerStream = Delegate.create(this, requestPlayerStream );
}
function getPlaybackTime():Number {
// trace("OP Adapter: returning playback time: " + playbackTime);
return playbackTime;
}
function requestPlayerPlay() {
if (getPlayerState() != "playing") {
sendEvent("playpause");
}
}
function requestPlayerPause() {
if (getPlayerState() != "paused") {
sendEvent("playpause");
}
}
function requestPlayerStream(streamURL:String, duration:Number) {
playbackDuration = undefined;
// This inserts an item into the feed after the currentItem, and then fires the event
// causing the controller to move to the next item.
feeder.addItem({file: streamURL, duration: duration}, controller["currentItem"]+1);
sendEvent("next");
}
/////////////// Outgoing Methods //////////////////////////////
function op_onLayoutSizeChanged(width:Number, height:Number) {
opContainer.onLayoutSizeChanged(width, height);
}
function op_onPlayerStateChanged(playerState:String) {
opContainer.onPlayerStateChanged(playerState);
}
function op_onPlayerVolumeChanged(playerVolume:Number) {
opContainer.onPlayerVolumeChanged(playerVolume);
}
// onUserScrubbing is not applicable to the JW Player since scrubbing (moving the playhead)
// does not actually change the current playtime while the playhead is being dragged.
// function op_onUserScrubbing(isScrubbing:Boolean) {
// opContainer.onUserScrubbing(isScrubbing);
// }
function op_onPlaybackDurationAvailable(duration:Number) {
opContainer.onPlaybackDurationAvailable(duration);
}
function op_onVideoEnd() {
opContainer.onVideoEnd();
}
// onUserInteractedWithPlayback is listed as optional in the Overstream Platform Specification,
// it is left unimplemented in this example.
// function op_onUserInteractedWithPlayback() {
// opContainer.onUserInteractedWithPlayback();
// }
/////////////// Utils /////////////////////////////////////////
// This breaks the view/controller abstraction barrier, better avoid it?
private function getPlayerState():String {
return controller["isPlaying"]?"playing":"paused";
}
////////////// JW View Event Callbacks
// on PlaybackTime update
private function setTime(elapsed:Number, remaining:Number) {
playbackTime = elapsed;
// Sometimes before the flv duration is available, remaining is passed as 0
if (remaining) {
var playbackDuration:Number = remaining + elapsed;
if (!this.playbackDuration) {
op_onPlaybackDurationAvailable(playbackDuration);
}
this.playbackDuration = playbackDuration;
}
}
private function setVolume(playerVolume:Number) {
this.playerVolume = playerVolume;
op_onPlayerVolumeChanged(playerVolume);
}
private function setState(playerStateNum:Number) {
// 0 is paused, 2 is playing, 3 is video ended (note that 3 fires for an invalid stream as well)
// trace("playerStateNum: " + playerStateNum);
if (playerStateNum == 3) {
this.playerState = "stopped";
op_onVideoEnd();
} else {
this.playerState = (playerStateNum==2)?"playing":"paused";
}
op_onPlayerStateChanged(playerState);
}
// Catches fullscreen escape
public function onFullScreen(fs:Boolean) {
if (fs) {
op_onLayoutSizeChanged(Stage.width, Stage.height);
} else {
op_onLayoutSizeChanged(config["displaywidth"], config["displayheight"]);
}
}
}