Wednesday, February 18, 2009

Size matter... Deep inside FLVplayback to reduce the size of the generated SWF

There is a nice balance between using the built-in Flash video components and doing your own thing to achieve the exact look and feel that you want as well as making sure the size of your SWF is small enough for what you want to do. Why ?
The answer is obvious. CDN company charges by the bandwidth so if you have a SWF on a web server which is supposed to stream a video without any user control make sure you don't build a SWF with controls. This might looks like a penny but if your ad is viewed by million of users, you end up winning some of the cost because of the size of the SWF. Finally, sometimes you are paying for the SWF and others for the content bandwidth. The new as3 version of FLVPlayback has some great features in it, including a sophisticated connection management and a well thought-out event system. However, over the years you've learned to avoid to using the standard Flash component set because there is always some sort of customization that your art director wants from you guys that the standard set just won't support.

The VideoPlayer class lets you create a video player with a slightly smaller SWF file than if you used the FLVPlayback component. Unlike the FLVPlayback component, the VideoPlayer class does not let you include a skin or playback controls, and although you cannot find or seek to cue points, the cuePoint events will occur. The FLVPlayback class wraps the VideoPlayer class. Use the FLVPlayback class in almost all cases because there is no functionality in the VideoPlayer class that cannot be accessed using the FLVPlayback class.

In practice the file size reduction of using VideoPlayer instead of FLVPlayback is on the order of 30kb. That's a nice savings bump, but it's probably irrelevant compared to the size of the video files. This 30kb savings is achieved by adding the classpath for the video playback package to the .fla file's classpath instead of just dragging the component icon into the library. For reference, here's the paths to add (File -> Publish Settings ->Flash -> ActionScript 3.0 Settings)


$(AppConfig)/Component Source/ActionScript 3.0/FLVPlayback

$(AppConfig)/Component Source/ActionScript 3.0/User Interface

So that's pretty easy, but there is one limitation that can was make your life complicated. If you are making use of all kinds of cool functions such asBitmapData.draw, SoundMixer.computeSpectrum, etc which require that your domain security ducks all be in a row. If you want to take Bitmap snapshots of a video as it's playing back. (FYI: this is an option only for video delivered using http progressive download and not for video delivered by rtsp stream coming out of Flash Media Server.) In as3 most classes which load remote files offer a means of telling the loader to check against the crossdomain.xml files that have already been loaded and if necessary, try and load the crossdomain.xml file from the new files' domain. This is handy, because you only request domain files when they are needed and you don't need to know the domains in advance. To trigger the domain checks Loader uses the LoaderContext class, Sound files use the SoundLoaderContext class, and video files use the checkPolicyFile property on the NetStream class.

So how do you set this flag when using the VideoPlayer or FLVPlayback components? Unfortunately, there is no method to do this in the existing api. VideoPlayer is an excellent wrapper around NetConnection and NetStream, however you cannot set properties directly on the NetStream object from outside the VideoPlayer thus leaving the checkPolicyFile property stuck at the false setting. What to do? Extend the class and set the flag yourself. Here's some code for a VideoPlayerExtended class:

package {import fl.video.*;

import flash.events.NetStatusEvent;
import flash.net.NetStream;

use namespace flvplayback_internal;

/**
* Extended version of fl.video.VideoPlayer class.
*/

public class VideoPlayerExtended extends VideoPlayer {

/**
* Override the default means of creating a netstream object
*
* Add checkPolicyFile=true to force loading of a crossdomain.xml file
*
* @private
*/
flvplayback_internal override function _createStream():void {
_ns = null;
var theNS:NetStream = new NetStream(_ncMgr.netConnection);
if (_ncMgr.isRTMP) {
theNS.addEventListener(NetStatusEvent.NET_STATUS, rtmpNetStatus);
} else {
theNS.addEventListener(NetStatusEvent.NET_STATUS, httpNetStatus);
}
theNS.client = new VideoPlayerClient(this);
theNS.bufferTime = _bufferTime;
theNS.soundTransform = soundTransform;
theNS.checkPolicyFile = true;
_ns = theNS;
attachNetStream(_ns);
}
}
}

You may be interested to read more about interactive video in Flash CS4 as well
using FLVPlayback Component or NetStream AS3 Class

http://younsi.blogspot.com/2008/12/interactive-video-in-flash-using-f4v.html

3 comments:

gregbown said...

Thanks for the tip. I am using the fl.video classes directly in flex so all I had to do is add one line inside the _createStream() function in fl.video.VideoPlayer

_ns.checkPolicyFile = true;

Now if I could just get rid of Unhandled NetStatusEvent:. level=error, code=NetConnection.Call.Failed

Anonymous said...

how about this for setting checkPolicyFile:

myFlvPlayer.getVideoPlayer(myFlvPlayer.visibleVideoPlayerIndex).netStream.checkPolicyFile = true;

Thomas Younsi said...

You may be interested to read more about interactive video in Flash CS4

http://younsi.blogspot.com/2008/12/interactive-video-in-flash-using-f4v.html