b-log – betriebsraum weblog

Software Development, Human-Computer Interaction, Projects…

Flash Video Tip 1: Calculating an optimal buffer size

February 27, 2007

Sorry for not posting much the last weeks/months… This article is the start of a few tips about flash video and deals with calculating the buffer size for a flv video.

If you want to display a flash video file you have primarily three options:

  1. Ignore the user’s bandwidth and just display the version you have encoded, use an estimated buffer size
  2. Display different versions of the same file (e.g. a low, medium or high version) depending on the user’s bandwidth, use an estimated buffer size or additionally calculate the optimal buffer size
  3. Display a reasonable encoded version and calculate an optimal buffer size depending on the user’s bandwidth

Please note that I’m speaking of progressive download flv’s and not streaming flv’s here (with very long videos real streaming is almost always the better choice) and using external flv’s (embedding the video into the swf is suitable only for very short sequences).

Of course it’s completely based on the situation how and where you want to show the video but generally option 1 is only preferable if your video is well encoded and you exactely know your target audience. Option 2 causes the most effort up front (encode different versions…) but is very suitable if you can live with the fact that users with low bandwidth see a poor quality version of your video. Option 3 lies somewhere between 1 and 2 and is something you can always do without too much effort.

How can the buffer size be calculated? You need to know three values:

  1. The length of your flv file in seconds
  2. The bitrate of your flv file in kilobits per second
  3. The user’s bandwidth in kilobits per second

If you know these values you can calculate the buffer size by a simple formula. Where do you get these values from? The first (length of flv file) can be found in the flv’s metadata property which is set when you encode your video (e.g with flash 8 video encoder), the seond (bitrate of flv) can also be found in the metadata property.
The third is more complicated as there’s no built-in property or method in flash which returns the user’s bandwidth, so you have to find out that value by a bandwidth check (which you can do the first time when the user visits your application, for example).

The formula for calculating the buffer size is the same as you can find in Adobe Devnet with the main difference that it’s encapsulated in an own class here. You may find it “overkill” to put just one method with a few lines of code into an own class but it’s convenient if you want to reuse it in other projects. Furthermore you could put in more static video utility methods and perhaps change the name of the class to something like “VideoUtil”.

Here’s the BufferCalculator.as:

class de.betriebsraum.video.BufferCalculator {
	// buffer padding in sec.
	// should be at least twice as long as the keyframe interval and fps, e.g.:
	// keyframe interval of 30 at 30fps --> min. 2 sec.
	public static var BUFFER_PADDING:Number = 3;
 
	public function BufferCalculator() {
 
	}
 
	// flvLength in sec., flvBitrate and bandwidth in kBits/Sec
	public static function calculate(flvLength:Number, flvBitrate:Number, bandwidth:Number):Number {
	 	var bufferTime:Number;
		if (flvBitrate > bandwidth) {
			bufferTime = Math.ceil(flvLength - flvLength / (flvBitrate / bandwidth));
		} else {
			bufferTime = 0;
		}
		bufferTime += BUFFER_PADDING;
 
		return bufferTime;
	}
 
}

If you have a video file with a length of 30 seconds, 400 kbps bitrate and a bandwidth of 768 kbps, you can set the buffer size like this:

import de.betriebsraum.video.BufferCalculator;
myFlvPlayback.bufferSize = BufferCalculator.calculate(30, 400, 768);

(The BufferCalulator.as is contained in the example-zip which you can download at the end of this article).

The next part is about how to actually get the values which you have to plug into the calculate() method. If you don’t have an own method for calculating the bandwidth, you could use our BandwidthDetector class (updated it some weeks ago). In the download-zip you can find a commented example file how to use the class. Basically it loads a file you can specify for a number of seconds and then figures out what the average bandwidth is. The nice thing is that you only have to do this check once (e.g. on application startup). The class can store the value in a shared object and triggers the check again when the time has expired. Of course this method isn’t bullet-proof: The user’s bandwidth can vary while using your application etc. but it’s better than nothing. The following example demonstrates how to use the BufferCalculator and BandwidthDetector together with a (Flash 8) FLVPlayback component (code put in frame 1):

Stage.scaleMode= "noScale";
 
import de.betriebsraum.loading.BandwidthDetector;
import de.betriebsraum.video.BufferCalculator;
import mx.utils.Delegate;
 
var BANDWIDTH:Number;
 
function onBwDetect(evObj:Object):Void {
	BANDWIDTH = evObj.data.kBitsSec;
	fp.contentPath = "flv/trusted_computing.flv";
}
 
function onFlvMetaData(evObj:Object):Void {
	fp.bufferTime = isNaN(BANDWIDTH) ? 3 : BufferCalculator.calculate(fp.metadata.duration, fp.metadata.videodatarate, BANDWIDTH);
}
 
function init():Void {
	fp.addEventListener("metadataReceived", Delegate.create(this, onFlvMetaData));
 
	var bwDetector:BandwidthDetector = new BandwidthDetector(this, 0);
	bwDetector.addEventListener("onDetect", Delegate.create(this, onBwDetect));
	bwDetector.expireTime = 86400;
	bwDetector.detect("img/bandwidthCheck.jpg", 3);
}
 
init();

You could furher enhance this but putting the code of frame 1 in a separate main class and by encapsulting the bandwidth detection and buffer calculating behaviour into a decorator class for a FLVPlayback component, so that every time you instantiate a new FLVPlayback in your application it automatically sets its bufferSize property – that’s a nice »addon« but more important is to make sure your flv file is encoded with the correct bitrate, keyframe interval etc.. There are a few Adobe Devnet articles where you can find more information about flash video encoding best practices.

Download the example files.

(The flv I used here is a part of the great »Trusted Computing« movie. You can watch the full-length movie at lafkon.net. The bandwidth testfile is a wallpaper which I found somewhere some time ago (sorry, cannot remember where…)

Filed under: Flex/AS3

17 Responses to “Flash Video Tip 1: Calculating an optimal buffer size”

  1. nice one, this will come in handy

  2. […] Calculating an optimal buffer size. […]

  3. Michael says:

    Not sure about

    import de.betriebsraum.video.BufferCalculator;

    Do you mean that this needs to be pluggedin to the App? If so how does one do that?

    My FLv is 700Mbs and is 2333 seconds long. I have made the buffer in properties 33 sec’s. But it makes the video stream an then buffer again every 7 to 10 minutes

    Your method if put in fram 1 layer “Actions” it should improve the process?

    How do I input the variables?

  4. Michael says:

    **Error** Scene=Scene 1, layer=Actions, frame=1:Line 27: The class or interface ‘de.betriebsraum.loading.BandwidthDetector’ could not be loaded.
    var bwDetector:BandwidthDetector = new BandwidthDetector(this, 0);

    Total ActionScript Errors: 1 Reported Errors: 1

    This error when published

  5. Michael says:

    Try this site

    http://0063c7e.netsolhost.com/BWTest/index.html

    It is with the script and the .as files on the server.

    Not working

    I would like to use it, but I am not a developer. Just a enthusiast.

  6. felix says:

    Hi Michael,

    first…for a videolength of about 40 minutes you should use streaming video and are you really sure you mean 700 mbps and not 700 kbps? I don’t think you can play a 40 minutes flv with 700 mbps datarate without rebuffering (except your bandwidth is about 1 gbps or so ;)

    To fix the compiler error you have to set the correct classpath in your fla file (under publish settings/actionscript settings…).

  7. Michael says:

    Felix

    Danka
    What do I set the class to? You are correct 700Kbps is the encoded size. The File is 256Mbs I calculate the time as 2333 Seconds or 42 minutes.

  8. Michael says:

    Felix

    I have found the locaton of the class path. What to put in it?

  9. Michael says:

    Same error

    I put../src in the class is that correct?

    **Error** Scene=Scene 1, layer=Actions, frame=1:Line 27: The class or interface ‘de.betriebsraum.loading.BandwidthDetector’ could not be loaded.
    var bwDetector:BandwidthDetector = new BandwidthDetector(this, 0);

    Total ActionScript Errors: 1 Reported Errors: 1

  10. Michael says:

    ../src is a location for the files? My src folder is on this pathe D:\Bandwidth\src\folder\folder\ (etc)

    Should the class be a location?

  11. Michael says:

    http://0063c7e.netsolhost.com/BWTest/index.html

    Felix

    Please check this out. The src folder is now in the root of //htdocs/src

    the swf file is in the //htdocs/BWTest folder

    When the AS is run the video does not play

    Any thoughts?

  12. Michael says:

    Error opening URL “file:///D|/Bandwidth/img/bandwidthCheck.jpg”

  13. […] Flash Video Tip 1: Calculating an optimal buffer size […]

  14. Brandon says:

    I’m attempting to convert this to AS3… First run gave a “compile-time constant” error on “MovieClip”.

    I imported all of “import flash.display.*” and still get it…

    Have you moved this code to AS3, and dealt with the nuances, yet?

  15. felix says:

    Hi Brandon,

    just send me your AS3 code, then I’ll look through it…

  16. […] isn’t entirely foolproof. Its drawbacks have been documented by almost everybody who’s written written on the subject so I won’t go into it. However, since the actual detection is […]

Add a comment

Follow comments to this post by subscribing to the comment feed.