extending the flash videoplayer class to load the crossdomain.xml file on demand

I’ve been doing lots of Flash video streaming work using ActionScript 3 and I’ve found a nice balance between using the built-in Flash video components and doing my own thing to achieve the exact look and feel that I want. The new as3 version of FLVPlayback has some great features in it, including sophisticated connection management and a well thought out event system. However over the years I’ve learned to avoid to using the standard Flash component set because there is always some sort of customization that my art director wants which the standard set just won’t support. Grant Skinner’s new component architecture in Flash CS3 is a tremendous step forward and I do like the Button and ScrollPane components but I have still found that the options on customizing the skin of something like the Slider are still too limited. At the end of the day, I couldn’t afford to be limited by the options in FLVPlayback. What to do?

In my case, I thanked the architects of the FLVPlayback component for their foresight and used the base fl.video.VideoPlayer class to create my own playback component wrapper. The documentation seems to discourage this as unnecessary,

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 I’ve found that 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 I found that there was one limitation that was making life complicated for me. I’m making use of all kinds of cool functions (BitmapData.draw, SoundMixer.computeSpectrum, etc) which require that my domain security ducks all be in a row. In this case I 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.) 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 my 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.
     * @see http://www.marstonstudio.com/?p=45
     * @author Jonathan Marston
     * @version 2007.12.26
     * This work is licensed under a Creative Commons Attribution NonCommercial ShareAlike 3.0 License.
     * @see http://creativecommons.org/licenses/by-nc-sa/3.0/

    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;

Note that the method is defined in the flvplayback_internal namespace as opposed to the more familiar public or private namespaces.

It probably would be best to make this a property that can be turned on and off from outside the class, but I found I always wanted it to be set to true so I didn’t go that extra step.


#1 siraj khan on 01.26.08 at 8:06 am

nice article… Jon :)

#2 matt on 10.10.08 at 8:49 am

Thats a cool idea. If you are using the FLVPlayback component, how do you get it to instantiate a new VideoPlayerExtended instead of a new VideoPlayer if its a compiled clip or a swc?

Would you have to extend FLVPlayback and then override VideoPlayer?



#3 Caleb on 01.14.09 at 4:37 pm

Very nice work, you saved me countless hours trying to track down how to fix that bitmap.draw sandbox issue. Thanks!