Newsletter: Learn More ||| Multimedia Presentation Software |||
Creating an Adaptive Preloader in Flash 5+
 
Note: Flix Pro will automatically create an adaptive preloader for your Flix-encoded files.
 
Contents
Download the FLA for Flash 5+ and a sample video file here.
Top
Introduction
This tutorial and FLA explains how to construct an adaptive preloader for your Flix encoded video. An adaptive preloader will preload a variable amount of your video based on the size of the video and the viewer's internet connection speed so that the viewer can watch the video without stops and starts - no matter what speed they are connected to the internet at.

A preloader is a piece of code that causes the Flash Player to load a specified percentage of your Flix encoded video prior to beginning playback. The purpose of the preloader is to ensure smooth playback of larger videos for users on slower connections. In this way, users on slower speed connections (e.g., dial up modems) can view larger, higher quality video files without buffering or the video stopping and starting. For instance, if someone on a 56k connection tries to view a video that was encoded for a 256k connection, the video is still going to play, but the amount of information contained in each frame of the video will be much larger than it would be for a video specifically encoded for a 56k connection. This will cause an inconsistent and choppy playback experience for the 56k user. The purpose of a preloader is to ensure that enough of the video has loaded that there will be no interruption once the video begins to play. While there is a delay while the user waits for the video to begin playback, if you preload enough of the file, once it starts to play, it will continue to play uninterrupted until it finishes.

A key issue in using a preloader is deciding how much of your Flix video you want to preload before beginning playback. One way to deal with the problem is by choosing to preload 100% of the video prior to playback. In this way, you know that all viewers will have the entire video loaded before the video starts to play. But this also means that users on a slow connection can wait a long time for the video to start playing. And if people have to wait too long, they may just surf away. Wouldn't it be nice if your preloader was "smart" and knew exactly how much of the video it had to load before beginning playback based on the user's connection speed and the video file size for the video to play uninterrupted once it started?

That is exactly what this adaptive preloader does. It determines the user's connection speed and based on that figure and the size of the video file you are preloading, it preloads precisely the amount of the video required to enable the video to begin playing as soon as it possibly can and still not stop at any point until it is done. In this way, the preload process is optimized so the amount of time taken for a video to preload is minimized as much as possible based on the speed of the viewer's connection and the size of the video they are viewing. The adaptive preloader will cause the video to begin playing as quickly as possible (as opposed to waiting until an exact amount of the video is preloaded) because it calculates the optimal preload amount and begins playing the video as soon as possible. It does not have to wait a fixed amount of time. The preloader literally adapts to the viewer's conditions.

Here are a few helpful hints about working with this tutorial:
  • Actionscript Code is highlighted in this color.
  • Flash Actionscript starts with
    //~ Actionscript BEGIN
    and ends with
    //~ Actionscript END
  • Predefined functions, words and properties are bold.
  • Comments are highlighted in this color.
  • Values referencing to Actionscript code are written in italics.
Top
Information we need
Before we start moving directly into the code I want to give a short explanation of the logic behind the adaptive preloader.

The logic of the adaptive preloader is as follows:

We have to load precisely the appropriate amount of the Flix video so the rest of the video can be loaded in the time the preloaded portion is displayed. Nice, huh :-)

In other words:
  • We start loading the Flix video file, but we do not display it until the appropriate time. (We start the loadMovie() command, but at the same time we prevent the movie from starting to play with a stop()-action)
  • We determine how long it should take for the Flix video file to completely load. (with the getBytesLoaded() and getTimer() commands we can determine the approximate time it will take for the Flix video file to completely load)
  • We determine how long it will take to display the loaded portion of the video file.
    (we know how many bytes we have loaded and we know the framerate - with this information we can determine how long - approximately - the playing time of the loaded portion of the video file)
  • If the time it should take to display the loaded portion of the video is longer than the time we need to load the rest of the video file, we start playing the video. (we have two values, one value shows how long we need to load the SWF-file up to the end and the other value shows how long it will take to display the loaded portion of the video file. If the time it should take to display the loaded portion of the video is longer than the time we need to load the rest of the video file, we can start playing the video and while it plays the rest of the video is loaded.
First, we have to determine the visitor's connection speed (in kilobytes). Therefore we need the following information:
  • how much time has elapsed since we started loading the video (in milliseconds)
  • how much of the video has been loaded in this time (in bytes)
This gives us the following logic:

    loaded kilobytes
connection speed (in kilobytes per second) = -------------------------------
    loading time in seconds


In Flash that would be (simplified):
//~ Actionscript BEGIN
loadMovie("file.swf","_root.mc");
startTime = getTimer();
cSpeed = _root.mc.getBytesLoaded() / getTimer() - startTime;
//~ Actionscript END


We have to determine the playing time of the video (in seconds), therefore we need the following information:
  • the framerate (frames per second) of the video the total number of SWF frames in the video
This gives us the following logic:
    total frames
total playing time (in seconds) = -------------------------------
    framerate

In Flash that would be (simplified):
//~ Actionscript BEGIN
fps = 12;
totalFrames = _root.mc._totalframes;
totalTime = totalFrames / fps;
//~ Actionscript END


We also have to determine how long the playing time of the loaded portion of the video is (in seconds). Therefore we need the following information:
  • the framerate (frames per second) of the SWF
  • the count of already loaded frames
This gives us the following logic:

    loaded frames
playing time (in seconds) = -------------------------------
    framerate


In Flash that would be (simplified):
//~ Actionscript BEGIN
fps = 12;
loadedFrames = _root.mc._framesloaded;
playTime = loadedFrames / fps;
//~ Actionscript END


Next, we have to determine the time that would be required to load the video to the end (in seconds). Therefore we need the following information:

  • how much do we still have to load (in kilobytes)
  • the visitors connection speed (in kilobytes per second)
This gives us the following logic:
    kilobytes we still have to load
remaining loading time (in seconds) = -------------------------------
    connection speed (in kilobytes per second)


In Flash that would be (simplified):
//~ Actionscript BEGIN
bytesToLoad = _root.mc.getBytesTotal() - _root.mc.getBytesLoaded();
kiloBytesToLoad = bytesToLoad / 1024;
leftLoadTime = kiloBytesToLoad / cSpeed; //~ we determined cSpeed before, see above.
//~ Actionscript END

Top
Coding
Now let's go into the code.
 
 
Explanation of the Code
 
The
FLA file included with this tutorial contains more code than the picture
shown above, including a movieclip prototype loadAdaptive(). But in this
tutorial I will only explain the code of the two most important frames
- the code which makes this preloader an adaptive preloader.
 
Start of loading
 
Somewhere before the code in the frame calculate the loading of the external video is started to a movieclip named the value of this.target. Also a variable has been created right after the start of the loading. Its name is startTime.

So an example code before this point would be:
//~ Actionscript BEGIN
this.target = "_root.mc";
loadMovie("file.swf",this.target);
startTime = getTimer();
gotoAndPlay("calculate"); //~ calculate is the name of the frame with the code below
//~ Actionscript END
 
Adaptive Loading
 
This is the frame with the name calculate:

First of all we need to define the framerate of the video to be loaded. For this tutorial we will use a video with a SWF framerate of 12 fps (frames per second).

//~ Actionscript BEGIN
//~ frames per second of the video
fps = 12;
//~ Actionscript END


Then we need to define a buffer factor. This will cause the preloader to preload more (or less) of the video than the initial calculations determine is the minimum amount of time required. This is useful because a viewer's connection speed often varies, even during the course of watching a single video. The time we need to load the SWF-file up to the end is multiplied with this factor. If you don't want to use a buffer you set the factor to 1.0 (a factor of 1.0 means NO buffer - loadingTime * 1.0 = loadingTime). But I recommend using a factor larger than 1.0 to be on the safe side.
  • If you think the viewer's connection will get faster during the visit (e.g., perhaps a download ends) then you can change the buffer factor to a number smaller than 1.0.
  • If you think the viewer's connection will get slower during the visit (e.g., because the viewer starts a new download) you should change the buffer factor to a number greater than 1.0. I always recommend making it larger than 1.0 to be on the safe side. A value of 1.1 gave good results with a 56k Modem in my tests.

//~ Actionscript BEGIN
/*~ define a puffer factor (in case the connection differs during the visit)
set 1.0 for NO puffer */
pufferFactor = 1.1;
//~ ############### END OF USER-DEFINED OPTIONS ###############
//~ Actionscript END


Next we need some information from the video which is loaded:

//~ Actionscript BEGIN
//~ total bytes of the swf
totalBytes = eval(this.target).getBytesTotal();
//~ total frames of the swf
totalFrames = eval(this.target)._totalframes;
//~ actual frame of the swf
currentFrame = eval(this.target)._currentframe;
//~ loaded bytes of the swf
loadedBytes = eval(this.target).getBytesLoaded();
//~ loaded frames of the swf
loadedFrames = eval(this.target)._framesloaded;
//~ Actionscript END


Next we have to determine this information:

//~ Actionscript BEGIN
//~ bytes still to load
leftBytes = totalBytes - loadedBytes;
//~ time since loading started (in milliseconds)
loadTime = getTimer() - this.startTime; //~ Variable startTime
//~ determine connection speed (in KB/second)
speed = loadedBytes / loadTime;
//~ determine total playing time of the movie
totalTime = totalFrames / fps;
//~ determine time currently could be played (in seconds)
playTime = loadedFrames / fps;
//~ determine time which is needed to complete loading of the swf (in seconds)
leftLoadTime = (leftBytes / 1024) / speed;
//~ Actionscript END


Once the preloader has all this information, it can determine whether or not to start the video, or if it should wait longer - until the time it will take to display the loaded portion of the video is longer than the time we need to load the rest of the video.

I just want to make a couple of comments about the loading bug in Flash 5+. If you load a SWF file with loadMovie() and then watch the values of the property getBytesLoaded() and getBytesTotal() you will see, that they will have the same value (normally 22) for several milliseconds. Now if you check this value using some code like getBytesLoaded() == getBytesTotal() this will return true (which is incorrect) for several milliseconds and that can cause problems in our code. This is why we use another variables.

//~ Actionscript BEGIN Prevent loading bug
s = totalFrames / currentFrame;

if (s > 1 || once == true) {
/*~ if time which can be displayed is longer
than the time needed to load start the swf */
if (playTime > (leftLoadTime * pufferFactor) && once == false) {
status = "playing...";
eval(this.target).play();
once = true;
//~ if playing ended, stop the swf
} else if (currentFrame == totalFrames && once == true) {
status = "finished playing...";
eval(this.target).stop();
this.stop();
}
//~ we still need some time for loading
} else {
eval(this.target).stop();
status = "buffering...";
}
//~ Actionscript END

 
Jumping back
 

The Code above in the frame calculate needs to be executed until the video is displayed entirely, therefore we need to jump backward to this frame.
The following code in the frame after calculate will do that:

//~ Actionscript BEGIN
//~ jump backward
gotoAndPlay(_currentframe - 1);
//~ Actionscript END

Top
Example/Test
You can see an example of the adaptive preloader in action here. Depending on how fast your connection is it may take several minutes until the video starts.

If you want to test your own adaptive preloader with your video files and you don't have a modem or another slow connection for testing, you can download the xat.com Webspeed simulator here (http://www.xat.com/wo/index.html). With this simulator you can define your connection and test the working of your adaptive preloader offline.

Have fun with this adaptive preloader and best wishes for your current and future projects.
Top
 
This tutorial was written by Josch Feth of Flashtool
 
©2007 Wildform, Inc | Policies | Contact Us | Newsletter Options
 
Wildform provides a 100% satisfaction guarantee on all our software. If you are not completely satisfied with our software for any reason you may request a refund within 15 days of purchase.