 |
| 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 |