Tutorial: Building a Flash Video Player in ActionScript 3 powered by JavaScript through ExternalInterface

This tutorial stems from the frustrations I recently encountered creating a Flash video player for a website, and I hope it will help others solve issues including:

  1. Having ActionScript 3 code in Flash pass variables back and forth with JavaScript using ExternalInterface in a way that works across multiple browsers, including Internet Explorer
  2. Embedding a Flash movie in a page with swfobject without using nested object tags

For my application, the player would need to exist as a single .swf file, but be able to play a video specified with on-page code. The player would also need to display a video-specific thumbnail, along with an on-screen play button (in addition to the controls in the video skin), before a video is played, and after playback finishes. The solution needed to be cross browser compatible (including Internet Explorer!) and would have to work with a site built on ASP Classic.

I was able to create a solution that uses on-page JavaScript to pass variables containing the thumbnail, skin, and video locations to the player, after checking that the Flash .swf was completely loaded. The solution, with a few modifications, can be customized to work with any website. The solution consists of three files:

  1. A standard swfobject JavaScript file
  2. The on-page JavaScript and HTML
  3. A Flash .swf movie

As well as two support files:

  1. A thumbnail, first-frame image file in .jpg format to display before the video is played
  2. A video in .flv format

Flash and ActionScript 3 Setup:

  1. Create a new Flash document with a type of ActionScript 3
  2. From the Components window, under the “Video” category, drag the FLVPlayback component to the stage.
  3. Delete the FLVPlayback component from the stage. Notice that it remains in the project library.
  4. Create a new symbol, tick the “Export for ActionScript” and “Export in frame 1″ checkboxes, and give the symbol a class of “buttonPlay”. Make sure the symbol is deleted from the stage, but is still in the library with a Linkage property of “Export: buttonPlay”. This symbol will be overlayed atop the thumnail when the .swf is loaded, and will disappear along with the thumbnail when it is clicked or the video is played via the skin, and re-appear after the video has finished playing.
  5. Set your stage size to 400×225px (Customize this to whatever size you want the video to appear on your page. If you want to set the size of your player on a page-by-page basis, you can set your preferred stage size within the embed code, and can add width and height variables to the JavaScript playVideo function, and then set the FLVPlayback’s video.width and video.heigh values by amending the processInput function within the ActionScript.)

Paste the following ActionScript 3 code into the first frame:

//Import
import flash.external.*;
import fl.video.*;
import flash.display.MovieClip;
import flash.display.Loader;
import flash.events.*;
import flash.net.URLRequest;

//Declare variables
//Video variables
var currentVideo:String="defaultVideo.flv";
//Image variables
var imageAddress:String="defaultImage.jpg";
var imageLoader:Loader = new Loader();

//Create video player
var video:FLVPlayback=new FLVPlayback();
//Add the video player to the stage
addChild(video);
video.skinBackgroundColor=0x64737E;
video.skinBackgroundAlpha=1.00;
video.volume=1;
video.autoPlay=false;
video.width=400;
video.height=225;
video.x=0;
video.y=0;

//Create thumbnail movieclip
var thumbnail:MovieClip = new MovieClip();
thumbnail.x=0;
thumbnail.y=0;
//Add the thumbnail movieclip to the stage
addChild(thumbnail);

//Create buttonPlayOverlay movieclip
var buttonPlayMovieclip:buttonPlay = new buttonPlay();

//Read in variables from Javascript
ExternalInterface.addCallback("sendInput", processInput);
function processInput(inputOne, inputTwo, inputThree) {
	//Load video skin
	video.skin=inputOne;

	//Load thumbnail image
	imageAddress=inputTwo;
	var imageRequest=new URLRequest(imageAddress);
	imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
	imageLoader.load(imageRequest);
	function onComplete(evt:Event) {
		thumbnail.addChild(imageLoader.content);
		//Position buttonPlayMovieclip
		buttonPlayMovieclip.x=170;
		buttonPlayMovieclip.y=83;
		//Add the buttonPlayOverlay movieclip to the stage inside the thumbnail movieclip
		thumbnail.addChild(buttonPlayMovieclip);
	}

	//Load video
	currentVideo=inputThree;
	video.source=currentVideo;
}

//Listen for when buttonPlayMovieclip is clicked
buttonPlayMovieclip.addEventListener(MouseEvent.MOUSE_DOWN, playVideo);
//Play video and hide thumbnail
function playVideo(event:MouseEvent):void {
	video.play();
	thumbnail.x=-500;
}

//Listen for when the video is played
video.addEventListener(VideoEvent.PLAYING_STATE_ENTERED, hideThumbnail);
//Listen for when the video finishes playing
video.addEventListener(VideoEvent.COMPLETE, showThumbnail);

//Hide the thumbnail movieclip and play the video
function hideThumbnail(event:VideoEvent):void {
	video.play();
	thumbnail.x=-500;
}
//Pause the video and show the thumbnail movieclip
function showThumbnail(event:VideoEvent):void {
	video.pause();
	thumbnail.x=0;
}

//Tell JavaScript to load variables since at this point the swf has finished loading
ExternalInterface.call('swfReady');

After inserting the code, save your project as “videoPlayer.fla” and publish “videoPlayer.swf”

Page Setup:

The largest hurdle I had to overcome with the player was getting the embed to work correctly. The following examples assume that your files are at the following directory locations

  • HTML or ASP at www.example.com/directory/document.html
  • .swf file at www.example.com/flash/video/videoPlayer.swf
  • .swp video player skin at www.example.com/flash/video/skin.swf
  • .flv file at www.example.com/flash/video/movie.flv
  • .jpg file for the thumbnail at www.example.com/flash/video/image.jpg
  • swfobject .js file at www.example.com/includes/js/swfobject.js

The most important thing to remember when defining your asset paths is that, with ActionScript 3, the path of the .flv must be relative to the main player .swf, while the other files should all have paths defined relative to the HTML or ASP document in which your embedding the video player.

To embed the main videoPlayer.swf, a standard Flash short embed using code similar to this,

<object width="400" height="270">
	<param name="movie" value="../flash/video/videoPlayer.swf">
	<embed src="../flash/video/videoPlayer.swf" width="400" height="270"></embed>
</object>

works correctly in some browsers, but breaks in Internet Explorer. A quick Google search confirmed that using a swfobject embed method would allow Flash to access the on-page JavaScript.

Because the player was designed for a site that features a global header via ASP server side includes which I did not want to modify with any if statements, I needed the embed code block to be completely stand-alone. I include the swfobject JavaScript code within the video player embed code block, but it is probably more appropriate the include it in the page header. On most servers, your embed code should look like this:

<!-- Begin embed video -->
<script type="text/javascript" src="../includes/js/swfobject.js"></script>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="400" height="270">
        <param name="movie" value="../flash/video/videoPlayer.swf" />
        <!--[if !IE]>-->
        <object type="application/x-shockwave-flash" data="../flash/video/videoPlayer.swf" width="400" height="270">
        <!--<![endif]-->
          <p>To view video, please download <a href="http://get.adobe.com/flashplayer/" target="_blank">Flash Player</a>.</p>
        <!--[if !IE]>-->
        </object>
        <!--<![endif]-->
      </object>
<script type="text/javascript">
	swfobject.registerObject("videoPlayer", "9.0.0", "../flash/video/videoPlayer.swf");
	function playVideo(inputOne, inputTwo, inputThree) {
		document.getElementById('videoPlayer').sendInput(inputOne, inputTwo, inputThree);
	}
	function swfReady() {
		playVideo('../flash/video/videoControls.swf', '../flash/video/image.jpg', 'movie.flv');
	}
</script>
<!-- End embed video -->

The above embed code includes the swfobject embed, and the block of JavaScript that communicates with ActionScript. The second JavaScript function is triggered by the last line of ActionScript, and passes the asset paths as variables to the first JavaScript function, which passes them to the .swf.

Since the site I built this player for runs on ASP Classic, there is an issue with nesting <object> tags. After a lot of searching, I found a solution which exploits Internet Explorer-specific comments to embed Flash using swfobject without the need for nested <object> tags. My final embed code looked like this:

<!-- Begin embed video -->
<script type="text/javascript" src="../includes/js/swfobject.js"></script>
<!--[if IE]>
<object id="videoPlayer" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="400" height="270">
	<param name="movie" value="../flash/video/videoPlayer.swf" />
	<div><p>To view video, please download <a href="http://get.adobe.com/flashplayer/" target="_blank">Flash Player</a>.</p></div>
</object>
<![endif]-->
<!--[if !IE]> <-->
<object id="videoPlayer" type="application/x-shockwave-flash" data="../flash/video/videoPlayer.swf" width="400" height="270">
	<div><p>To view video, please download <a href="http://get.adobe.com/flashplayer/" target="_blank">Flash Player</a>.</p></div>
</object>
<![endif]-->
<script type="text/javascript">
	swfobject.registerObject("videoPlayer", "9.0.0", "../flash/video/videoPlayer.swf");
	function playVideo(inputOne, inputTwo, inputThree) {
		document.getElementById('videoPlayer').sendInput(inputOne, inputTwo, inputThree);
	}
	function swfReady() {
		playVideo('../flash/video/videoControls.swf', '../flash/video/image.jpg', 'movie.flv');
	}
</script>
<!-- End embed video -->

I hope others can use this solution to build other projects. Flash is a dying medium, but for now, it is still the most widely-used video display method, and getting it to interact with in-page scripts is often difficult.

Jeff Haines is a multimedia designer and producer living and working in Annapolis, Maryland. Follow his twitter feed atwww.twitter.com/jeffreyahaines

Tags: , , , , , , , , ,

Leave a Reply