
In the following article I will try to give you a short insight on how to integrate plug-ins into the free and open-source Flash video player by Jeroen Wijering. All techniques described in this article worked with version 4.1.
There are some restrictions for commercial use of the player. You have to apply for a commercial license at http://www.jeroenwijering.com/?page=order
In my eyes this player is a masterpiece in structured programming regarding the MVC architectural pattern. The source is as modular as possible so it can easily modified to fit new requirements. As an example it can be adapted to display videos from other sources (e. g. YouTube) by adding a new class as a submodel
. The player allows skinning and provides a wide range of settings as well as an useful JavaScript interface. While the majority of possibilities is documented in the Wiki I could not find any helpful information about the plug-ins. Maybe due a lack of time, perhaps because this possibility could be used to emulate the functionality of longtail video – a side project of Jeroen Wijering.
But this is just speculation so let us start over! This article will not give you turnkey sources nor will it be a full tutorial on how this or that could be realized with the JW-Player. I presume that you have already been dealing with Adobe Flash in a basic matter, so you can use my depictions as foundation for your own projects.
You will need to have the kroeger 05/63 pixel font installed / activated to not break the default player skin layout!
First you should get the source files and create an HTML file which loads the JW-Player in order to set up a test-bench. In the next step we will create a Adobe Flash file to house our plug-in functionality. First and foremost the size and frame rate does not matter, however I suggest you to choose a size around 300x200 pixels – which should be both, somewhat around the default as well as slightly smaller than the default size and the smallest display, the video player should be used with. This way you can layout your plug-in and perhaps add a script for scalable display later. Wether you will use scripts or not, you need to define a function called initialize
. Otherwise the player will throw an error!
The plug-in swf should be published somewhere relative to your test HTML file at best similar to later production environments. In the following code snippets I will assume, that the plug-in is placed in a subdirectory media/flash/plugins/
and is called plug-in.swf.
We will now pass some values to the JW-Player swf making use of the so-called flashvars. (I am sorry, I really tried to find some information about flashvars on the official sites of Adobe. I could not find anything helpful even in the livedocs. Except some outdated samples for Flash 6 and the use with ActionScript 2.0 which in this case are best of a basic use to understand what we are talking about. Perhaps someone can help out here? As there are several common ways to implement Adobe Flash in todays webpages I will attach a short paragraph containing samples of flashvar use at the end of this article.) Let us give the JW-Player a hint where to look for the plug-in. Add the flashvar plugin with the relative path to our plug-in as value, in our case media/flash/plugins/plug-in.swf. Your HTML code should look somewhat like this:
<object type="application/x-shockwave-flash"
data="player.swf"
width="300px"
height="200px" >
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="true" />
<param name="flashvars" value="plugins=media/flash/plugins/plug-in.swf" />
<param name="quality" value="high" />
<p>Please get the Adobe Flash Player!</p>
</object>
Be sure to use the relative path originated at the HTML document – not the swf!
Yes, it is as easy as that! Now your plug-in should be loaded automatically. But wait! Offline everything works fine, but the Flash player is not able to find the plug-in on the server. After some investigation, we know why there are troubles: We have to navigate through the ActionScript package of the JW-Player to the main view class (com → jeroenwijering → player → View.as). Just at the end of the class header there is a private string directory
with an URL assigned as value: http://plugins.longtailvideo.com/
. Perhaps this is a hint at how the plug-in interface usually gains utilization. If you set the directory
value to be an empty string (like this private var directory:String = "";) the whole thing should work online. (Better way to solve this problem would be, take the deep dive into this piece of code and understand what really is happening here
before removing some hardcoded value.)
From now on the rest is just some ActionScript wherewith we can do some magic! Since the code of the video player is well-structured and nearly every event you could imagine is dispatched all you have to do is: listen to the certain part (Model, View, Controller) and invoke some action!
Here we go: Include the View-class and declare a variable to hold the reference to the players View-instance:
// includes
import com.jeroenwijering.player.View;
// variables
// Reference to View-instance of video player
var v_player:View;
At this point, lazy guys, there is no short version, no init
, no programmers stenography!
And again, Jeroen Wijering made life with plug-ins easy. If you set up a function called initialize
it will be called as soon as your plug-in is properly loaded by the player:
…
// Called after loading of plugin is completed
function initialize( par_playerView:View ) {
v_player = View( par_playerView );
trace( "do something useful" );
}
The simple call to do something does not help much. I will give you an example of what could come next. For example it would be handy if the plug-in content would be centered if the player is resized! Let us assume we have a movie clip containing a graphic (mc_content, movie clip registration point should be on the top left) which should be horizontally centered and positioned somewhere above the vertical center (since there is this nice button to start the playback). But this graphic should disappear on playback start. We have to start with adding some lines to our plug-ins code header
, furthermore we will instantiate a transition manager to handle a nice fade out of our plug-in content:
// imports
// video player stuff
import com.jeroenwijering.player.View;
import com.jeroenwijering.events.ModelEvent;
import com.jeroenwijering.events.ModelStates;
import com.jeroenwijering.events.ControllerEvent;
// eye candy
import fl.transitions.Fade;
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.Transition;
import fl.transitions.TransitionManager;
// variables
// Reference to View-instance of video player
var v_player:View;
// Transition manager
var trnsmngr_content:TransitionManager = new TransitionManager( mc_content );
// functions
// Configure standard transitions used to fade plugin content in and out
var obj_contentFadeOut:Object = new Object();
obj_contentFadeOut.type = Fade;
obj_contentFadeOut.direction = Transition.OUT;
obj_contentFadeOut.duration = .7;
obj_contentFadeOut.easing = Regular.easeOut;
var obj_contentFadeIn:Object = new Object();
obj_contentFadeIn.type = Fade;
obj_contentFadeIn.direction = Transition.IN;
obj_contentFadeIn.duration = .7;
obj_contentFadeIn.easing = Regular.easeOut;
…
Now we have to set up some functions to handle the positioning of the content elements and kick-off the vanishing of this content element on playback.
…
// Invoked on resize
function onPlayerResize( par_arg ) {
alignContent( Number( par_arg.data.width ), Number( par_arg.data.height ) );
}
// Align content movie clip
function alignContent( par_width:Number, par_height:Number ) {
mc_content.x = Number( par_width / 2 - mc_content.width / 2 );
mc_content.y = Number( par_height / 2 - ( mc_content.height + 40 ) );
}
// Invoked on status change of video player
// - if playback has finished: fade in plugin content
// - if playback is (re-)started: hide plugin content
function onPlayerStateChange( par_arg ) {
if( par_arg.data.newstate == "COMPLETED" ) {
trnsmngr_content.startTransition( obj_contentFadeIn );
}else if( par_arg.data.newstate == "PLAYING" && par_arg.data.oldstate == "COMPLETED" ) {
trnsmngr_content.startTransition( obj_contentFadeOut );
}
}
…
Obviously, the next thing to care about: event listeners! The listeners are registered in our initialize
function:
…
// Called after loading of plugin is completed
function initialize( par_playerView:View ) {
v_player = View( par_playerView );
v_player.addControllerListener( ControllerEvent.RESIZE, onPlayerResize );
v_player.addModelListener( ModelEvent.STATE, onPlayerStateChange );
alignContent( v_player.config.width, v_player.config.height );
}
Now everything should work fine. The content will be realigned if the player should ever be resized on runtime (not very likely) and faded out on playback start or in respectively on playback end. To initially align the content, there is one line added, which calls alignContent. For convenience, the whole clump of code:
// imports
// video player stuff
import com.jeroenwijering.player.View;
import com.jeroenwijering.events.ModelEvent;
import com.jeroenwijering.events.ModelStates;
import com.jeroenwijering.events.ControllerEvent;
// eye candy
import fl.transitions.Fade;
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.Transition;
import fl.transitions.TransitionManager;
// variables
// Reference to View-instance of video player
var v_player:View;
// Transition manager
var trnsmngr_content:TransitionManager = new TransitionManager( mc_content );
// functions
// Configure standard transitions used to fade plugin content in and out
var obj_contentFadeOut:Object = new Object();
obj_contentFadeOut.type = Fade;
obj_contentFadeOut.direction = Transition.OUT;
obj_contentFadeOut.duration = .7;
obj_contentFadeOut.easing = Regular.easeOut;
var obj_contentFadeIn:Object = new Object();
obj_contentFadeIn.type = Fade;
obj_contentFadeIn.direction = Transition.IN;
obj_contentFadeIn.duration = .7;
obj_contentFadeIn.easing = Regular.easeOut;
// Invoked on resize
function onPlayerResize( par_arg ) {
alignContent( Number( par_arg.data.width ), Number( par_arg.data.height ) );
}
// Align content movie clip
function alignContent( par_width:Number, par_height:Number ) {
mc_content.x = Number( par_width / 2 - mc_content.width / 2 );
mc_content.y = Number( par_height / 2 - ( mc_content.height + 40 ) );
}
// Invoked on status change of video player
// - if playback has finished: fade in plugin content
// - if playback is (re-)started: hide plugin content
function onPlayerStateChange( par_arg ) {
if( par_arg.data.newstate == "COMPLETED" ) {
trnsmngr_content.startTransition( obj_contentFadeIn );
}else if( par_arg.data.newstate == "PLAYING" && par_arg.data.oldstate == "COMPLETED" ) {
trnsmngr_content.startTransition( obj_contentFadeOut );
}
}
// Called after loading of plugin is completed
function initialize( par_playerView:View ) {
v_player = View( par_playerView );
v_player.addControllerListener( ControllerEvent.RESIZE, onPlayerResize );
v_player.addModelListener( ModelEvent.STATE, onPlayerStateChange );
alignContent( v_player.config.width, v_player.config.height );
}
There are some additional things you should know while working with this nice player and its plug-in possibilities. Let me give you some arbitrary dodges!
v_player.config.[any name]title. You just need a textfield and assign the value
v_player.config.title.v_player.config.volume, v_player.config.width, v_player.config.height, v_player.config.fullscreenv_player.skin.stage[ "displayState" ]defaultsobject!
v_player.sendEvent( [event], [value] )sendEventyou can take control of various parts of the player. Set volume to 50 % by using following code:
v_player.sendEvent( "VOLUME", 50 ), set player into fullscreen mode: v_player.sendEvent( "FULLSCREEN", true ) or seek to closest keyframe to second two: v_player.sendEvent( "SEEK", 2 ).v_player.addViewListener, v_player.addModelListener, v_player.addControllerListenereventspart of the player class package (com → jeroenwijering → events → *).
In the above samples, I assume you work in the plug-in of this tutorial. Otherwise the v_player has to be replaced by your reference to the View-instance of the JW-Player!
This article is not meant as a full featured tutorial to a full working this-and-that-performing plug-in, rather an insight on the different parts of plug-in programming for JW-Player with some short examples.
I am not quite sure about the legal matters on the use of JW-Player with altered code. So please check the information on Jeroen Wijerings homepage or contact him to assure you are not cracking anything besides the legal regulations here!
As mentioned before, there are several ways of integrating Flash files into webpages. Today a lot of people use JavaScript to embed Flash movies, there is the famous swfobject as well as the Standard Adobe Flash way to use AC_FL_RunContent. One main reason to use JavaScript is the outline rectangle the InternetExplorer shows up and which forces you to click on the Flash movie once, before you can interact with the movie. Moreover there is a check if the correct version of Adobe Flash Player is installed on the client machine.
Next we have the former standard way using markup with object- and embed-tags to integrate flash. Finally there is one possibility, first shown in an A List Apart article (for more information please visit: http://latrine.dgx.cz/how-to-correctly-insert-a-flash-into-xhtml) to integrate Flash XHTML-Strict valid with markup and without the embed-tag which is in fact a relic from times with Netscape.
For each of these methods I will give you a short code snippet on how to pass Flashvars. This is known and far from being new, but get this as a compact reference for the most popular ways to integrate Flash.
First the markup methods, in the following example the former standard way:
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com
/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"
width="300px"
height="200px" >
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="true" />
<param name="movie" value="player.swf" />
<param name="flashvars" value="plugins=media/flash/plugins/plug-in.swf&title=A%20shortfilm" />
<embed src="player.swf"
flashvars="plugins=media/flash/plugins/plug-in.swf&title=A%20shortfilm"
quality="high"
width="300px"
height="200px"
allowScriptAccess="sameDomain"
allowFullScreen="true"
type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/go/getflashplayer" />
<param name="quality" value="high" />
<p>Please get the Adobe Flash Player!</p>
</object>
In this example we pass the variables plugin
and title
to the swf. You can append as much variables as you needed, as long as you keep the pattern: seperate the variables using the ampersand &
, assign value by using the equal sign =
: &[variable name]=[value].
Now for the XHTML-Strict compatible method. Analogue to the sample at the beginning of this article, passing Flashvars would look like this:
<object type="application/x-shockwave-flash"
data="player.swf"
width="300px"
height="200px">
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="true" />
<param name="flashvars" value="plugins=media/flash/plugins/plug-in.swf&title=A%20shortfilm" />
<param name="quality" value="high" />
<p>Please get the Adobe Flash Player!</p>
</object>
Variable names must not contain any special characters (as usual in ActionScript), the values should be URL-encoded.
In the first example you have to declare the variables and values twice to assure, that every browser (using either the object- or the embed-tag) gets the correct values!
Since the JavaScript methods are kinda proprietary, you have to find the correct solution for every specific JavaScript Flash integration. So, the following examples feature specific code for the AS_FL_RunContent
(first) and the swfobject
(second) method:
<script language="javascript">
if (AC_FL_RunContent == 0) {
alert("This page requires \"AC_RunActiveContent.js\".");
} else {
AC_FL_RunContent(
'codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0',
'width', '300',
'height', '200',
'src', 'player',
'quality', 'high',
'pluginspage', 'http://www.macromedia.com/go/getflashplayer',
'id', 'player',
'name', 'player',
'allowFullScreen', 'true',
'allowScriptAccess','sameDomain',
'movie', 'player',
'FlashVars', 'plugin=media/flash/plugins/plug-in.swf&title=A%20shortfilm'
); //end AC code
}
</script>
<noscript>
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"
width="300"
height="200"
id="player"
align="middle" >
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="true" />
<param name="movie" value="player.swf" />
<param name="flashvars" value="plugins=media/flash/plugins/plug-in.swf&title=A%20shortfilm" />
<embed src="player.swf"
flashvars="plugins=media/flash/plugins/plug-in.swf&title=A%20shortfilm"
quality="high"
width="300"
height="200"
name="player"
allowScriptAccess="sameDomain"
allowFullScreen="true"
type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/go/getflashplayer" />
<param name="quality" value="high" />
<p>Please get the Adobe Flash Player!</p>
</object>
Be sure to pass the Flashvars in the JavaScript code, as well as in the object-tag as param-tag and in the embed-tag as attribute flashvars
.
Finally, the swfobject
method:
<script type="text/javascript" src="swfobject.js"></script>
<div id="playerContainer">
This is a flash video player.
</div>
<script type="text/javascript">
var so = new SWFObject("player.swf", "player", "300", "200", "9");
so.addVariable("plugin", "media/flash/plugins/plug-in.swf");
so.addVariable("title", "A shortfilm");
so.write("playerContainer");
</script>
The Flash source codes are uploaded here:
ZIP file containing plugin.fla
Set up an HTML document with flashvars plugins
and title
:
plugins=[path to plug-in.swf without extension]&title=[video title]
Outcome should be a headline showing the video title on the JW-Player splash screen
.