Friday, February 20, 2009

Frenglish humor

Some of you reading my blog may have noticed that I am not obviously born in USA because of the amount of english mistakes. I am certainly confident that some of you mostly engineer won't have any problem to read. According to a research at Cambridge University, it doesn't matter in what order the letters in a word are. The only important thing is that the first and last letter be in the right place. The rest can be a total mess and you can still read it without problem. This is because the human mind does not read every letter by itself, but the word as a whole

http://www.jtnimoy.net/itp/cambscramb/

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

Monday, February 16, 2009

How to convert XMP Cuepoint Time to Millisecond in AS3

Following my article

http://younsi.blogspot.com/2008/10/flv-cuepoints-in-flash-cs3-with-flash.html

I wanted to explain to the Flash Community how they can interpret XMP Cuepoint
in millisecond time that Flash Can understand

To synchronize an action for a cue point in an F4V video file, you must retrieve the cue point data from either the onMetaData() or the onXMPData() callback functions and trigger the cue point using the Timer class in ActionScript 3.0. For more information on F4V cue points, see Using onXMPData().


Each XMP Tracks do have a framerate value
first get the nTracksFrameRate and then for each cuepoint time
devide the value read from XMP by the TrackFrameRate and you will
now have a time in millisecond.


function getFLVCuepointsFromXMP(onXMPString:String):void {
var onXMPXML = new XML(onXMPString);
var onXMPTracksXML;
var onXMPCuepointsXML;
var cuePointCount:Number = 0;
var strFrameRate:String;
var nTracksFrameRate:Number;
var cuePoints:Array = new Array();
var cuePoint:Object;

// Set up namespaces to make referencing easier
var xmpDM:Namespace = new Namespace("http://ns.adobe.com/xmp/1.0/DynamicMedia/");
var rdf:Namespace = new Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#");

var strTracks:String = "";

if (verbose) {
trace("###### TRACKS");
}

// This iteration get all the Tracks
for each (var it:XML in onXMPXML..xmpDM::Tracks)
{
var strTrackName:String = it.rdf::Bag.rdf::li.rdf::Description.@xmpDM::trackName;
var strFrameRateXML:String = it.rdf::Bag.rdf::li.rdf::Description.@xmpDM::frameRate;
strFrameRate = strFrameRateXML.substr(1,strFrameRateXML.length);

nTracksFrameRate = Number(strFrameRate);

cuePoint["time"] = nStartTime/nTracksFrameRate;

............


Hope this will solve few headhaches...

Now implement a timer and sync your Cue Point the way you want using Action Script 3 code.

I am talking about the best use cases of XMP Cue points in an older
article

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

Saturday, February 07, 2009

ActionScript 2.0 to ActionScrip3.0 Migration

Livedocs


The following table describes the differences between ActionScript 2.0 and 3.0.
http://livedocs.adobe.com/flex/201/langref/index.html?migration.html&all-classes.html

Conversion Tool

PHP
A great PHP set of class and stand alone windows exe will do few automated translation for you.

Features include:

* Updates createTextField to new TextField() syntax. Sets x, y, width and height if they are not the default (0). Uses addChildAt unless getNextHighestDepth() is used for argument 2, in which case addChild is used. Parses the first parameter and uses it as the variable name unless it is not a simple string, in which case a temp name is used, and the original name is shown in a comment on top of the block. Pretty sweet.
* Updates getURL to new URLRequest syntax. Works as above.
* Updates var, function and class to public var, public function and public class to remove warnings as requested by my childhood hero Robert Penner. Parses the class to recognize block depth to not affect local vars and inline functions.
* Smarter class and package name recognition.
* Removes unnecessary imports in the same package as the current class.
* Should properly recognize various line endings (crossing fingers).

The zip now includes a command-line executable called convertas2as3 for those Windows users who don’t feel like installing PHP. The zip is pretty big because it includes the php libraries for Windows users. On other platforms you can run the command-line utility in src/convert.php by typing php convert.php at the command line.

Try it here, download it here


JAVA
A Java JAR package and command line batch available here
http://jobemakar.blogspot.com/2007/05/convert-actionscript-2-to-actionscript.html
It automatically creates the package syntax, converts Void to void, recursively walks subdirectories, and outputs to a new location. In addition to those things it allows you to use two simple but powerful tags to do custom replacement of specific lines of code during upconversion. For instance:
//@replace var numShots:int = 10;
var numShots:Number = 10;

comes out as:
var numShots:int = 10;

Installation/usage instructions are included in the zip.
http://www.electrotank.com/junk/jobe/AS2_to_AS3.zip


SOME BASIC AS2 TO AS3 CONVERSION SAMPLE

Color
Old version:

First up, the old setRGB method of the legacy Color class.In the old days of ActionScript 1.0 and 2.0, you would create a Color object with a movieclip instance as an argument in the constructor, then apply the setRGB method on this Color instance. It was a bit weird, as you never really directly “talked to” the MovieClip whose colour you wanted to change.

var col:Color = new Color(some_mc);
col.setRGB(0x123456);

New Code

This has changed with AS3. The Color class is something else entirely, and in its place as a colour manipulator, we have this: ColorTransform.

import flash.geom.ColorTransform;
import flash.geom.ColorTransform;// create a new ColorTransform object
var colTrans:ColorTransform = new ColorTransform();
colTrans.color = 0xFF9900;
colTrans.alphaMultiplier = 0;
some_mc.transform.colorTransform = colTrans;

So this would set the colour of the object, but also set its alpha to 0.

Movie Clip Loader

Old Code

this.mcPreview.alpha = 0;
this.mcPreview.mcLoader = new MovieClipLoader();
this.mcPreview.mcLoaderListener = new Object();
this.mcPreview.mcLoaderListener.onLoadInit = Proxy.create(this, previewImageLoaded);
this.mcPreview.mcLoader.addListener(this.mcPreview.mcLoaderListener);
this.mcPreview.mcLoader.loadClip(pPath, this.mcPreview);

public class Proxy
{
public static function create(oTarget : Object, fFunction : Function,... arguments) : Function
{
/* Create an array of the extra parameters passed to the method. Loop
through every element of the arguments array starting with index 2,
and add the element to the aParameters array.*/
var aParameters : Array = new Array();
for(var i : Number = 2;i < arguments.length; i++)
{
aParameters[i - 2] = arguments[i];
}

// Create a new function that will be the proxy function.
var fProxy : Function = function():void
{
/* The actual parameters to pass along to the method called by proxy
should be a concatenation of the arguments array of this function
and the aParameters array.*/
var aActualParameters : Array = arguments.concat(aParameters);

/* When the proxy function is called, use the apply( ) method to call
the method that is supposed to get called by proxy. The apply( )
method allows you to specify a different scope (oTarget) and pass
the parameters as an array.*/

fFunction.apply(oTarget, aActualParameters);
};

// Return the proxy function.
return fProxy;
}
}
}
addChild(loader);

New Code

import flash.events.*;
import flash.display.Loader;
import flash.net.URLRequest;

var url:String = http://www.yourfullyqualidieddomain.com/yourswftoload.swf?cachebusters='+new Date().getTime();
var loader:Loader=new Loader();
loader.contentLoaderInfo.addEventListener(Event.OPEN,loadinit); loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,loading);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,completes);
loader.load(new URLRequest(url));




TWEEN

OLD CODE

the migration of onMotionFinished an event triggered on completion of the old mx.transitions.Tween class. There is a new class:TweenEvent (fl.transitions.TweenEvent) It looked like this in AS2:

import mx.transitions.Tween;
import mx.transitions.easing.Regular;

class SlidingClass extends MovieClip {var xTween:Tween
// class constructor etc. not shown
function slideTo(xTarget:Number, frames:Number, callbackObj:Object, callbackFunc:Function) : Void {
xTween = new Tween (this, "_x", Regular.easeOut, this._x, xTarget, frames, false)
xTween.onMotionFinished = function() {callbackFunc.call(callbackObj);
};};


New Code

no need to pass the target object anymore - that is inherent in the function argument:

import fl.transitions.Tween;
import fl.transitions.TweenEvent;
import fl.transitions.easing.Regular;
var xTween:Tween;

function slideTo(xTarget:Number, frames:Number, func:Function) {
xTween = new Tween(this, "x", Regular.easeOut, this.x, xTarget, frames, false);
xTween.addEventListener(TweenEvent.MOTION_FINISH, func);};


Because of AS3 Event handling, a reference to the Tween is automatically passed to the target function as an Event datatype, via the “target” property.


OnPress

//code in AS 2
cornerplus1.onPress = function () {

startDrag(this);

}


Warning: 1090: Migration issue: The onPress event handler is not triggered automatically by Flash Player at run time in ActionScript 3.0. You must first register this handler for the event using addEventListener ( 'mouseDown', callback_handler).

NEW

// in AS 3 becomes

cornerplus1.addEventListener(MouseEvent.MOUSE_DOWN, dragFn);
function dragFn(event:MouseEvent){
event.target.startDrag();
};


LoadVars


OLD

var msg:LoadVars = new LoadVars();
var msgSent:LoadVars = new LoadVars();
msg.var1 = "one";
msg.var2 = "two";
msgSent.onLoad = function($success:Boolean):Void
{
if ($success)
{
trace("Message sent.");
}
else
{
trace("Message failed.");
}
};
msg.sendAndLoad("http://www.yourfullyqualifieddomain.com/script.php", msgSent);

NEW

var scriptRequest:URLRequest = new URLRequest("http://www.yourfullyqualifieddomain.com/script.php");

var scriptLoader:URLLoader = new URLLoader();
var scriptVars:URLVariables = new URLVariables();
scriptLoader.addEventListener(Event.COMPLETE, handleLoadSuccessful);
scriptLoader.addEventListener(IOErrorEvent.IO_ERROR, handleLoadError);
scriptVars.var1 = "one";
scriptVars.var2 = "two";
scriptRequest.method = URLRequestMethod.POST;
scriptRequest.data = scriptVars;
scriptLoader.load(scriptRequest);
function handleLoadSuccessful($evt:Event):void
{
trace("Message sent.");
}
function handleLoadError($evt:IOErrorEvent):void
{
trace("Message failed.");
}

http://www.yourfullyqualifieddomain.com/script.php?var1=one&var2=two


MovieClip

Creating new instances of a class has been greatly simplified in ActionScript 3.0. In previous versions of ActionScript, you needed to call createEmptyMovieClip() or createTextField() if you wanted to create a new MovieClip or TextField. Now, in ActionScript 3.0, you can simply call new MovieClip() or new TextField() directly, as shown in the following examples:

OLD

// AS2
this.createEmptyMovieClip("mc", this.getNextHighestDepth());
mc.beginFill(0xFF0000);
mc.moveTo(0, 0);
mc.lineTo(100, 0);
mc.lineTo(100, 80);
mc.lineTo(0, 80);
mc.lineTo(0, 0);
mc.endFill();
mc._x = 80;
mc._y = 60;

The previous code creates a new movie clip instance, draws a red rectangle which is 100x80 pixels, and moves the instance to 80,60 on the Stage. Compare that to the following code which does the exact same thing, although using the new drawRect() method instead of having to use the moveTo() and lineTo() methods:

NEW

// AS3
var mc:MovieClip = new MovieClip();
mc.graphics.beginFill(0xFF0000);
mc.graphics.drawRect(0, 0, 100, 80);
mc.graphics.endFill();
mc.x = 80;
mc.y = 60;
addChild(mc);

MovieClip

OLD

ReferenceError: Error #1056: Caused by Declaring Stage Instances Private
If you declare a stage instance private you get the message: "ReferenceError #1056 Cannot create property my_mc on StageIntanceDeclarationsClass"

This error occurs when you uncheck the "Declare Stage Instances Automatically" checkbox in the "ActionScript 3.0 Settings" dialogbox and proceed to declare stage instances as private variables in the class associated with the containing MovieClip.

A Note on Inheritances and Declaring Stage Instances:
You cannot choose to simply always declare stage instances automatically without forcing the use of inheritance in classes linked to MovieClip Symbols. If you have a class APrime which is derived from class A and APrime is linked to a MovieClip Symbol, all stage instances used in the base class A must be manually declared in class A. "Declare Stage Instances Automatically" only declares instances in the class linked to the MovieClip Symbol and does NOT make those references available to any base classes.

Example:
Assume that the class StageIntanceDeclarations is set as the class associated with a MovieClip which c0ntains the MovieClip my_mc. Then the following code will cause ReferenceError #1056 at runtime.



package
{
import flash.display.MovieClip;
public class StageIntanceDeclarations extends MovieClip
{
//Private Causes ReferenceError #1056
private var my_mc:MovieClip;
function StageIntanceDeclarations()
{
}
}
}



The output is as follows:
ReferenceError: Error #1056: Cannot create property my_mc on StageIntanceDeclarations.
at flash.display::Sprite/flash.display:Sprite::constructChildren()
at flash.display::Sprite$iinit()
at flash.display::MovieClip$iinit()
at TestStageIntanceDeclarationsBase$iinit()
at flash.display::Sprite/flash.display:Sprite::constructChildren()
at flash.display::Sprite$iinit()
at flash.display::MovieClip$iinit()

NEW

To avoid this error simply declare my_mc as public:
public var my_mc:MovieClip;


XML

OLD
NEW

undefined null Nan

OLD
NEW

Thursday, February 05, 2009

Flash CS3 to Flash CS4 migration awerness when using FLVPlayback

For those of you who are willing to open existing FLA created by Flash CS3 in Flash CS4 and if those FLA were referencing some instance of the FLVPlayback in the library only controlled by Action Script 3 code, you have to be careful when saving the FLA in Flash CS4 the first time.

Flash CS4 will ask you to migrate your FLA to CS4. Great ! you are MORE than welcome to do this if you were using Action Script 3 code to load video (obviously FLV) and now you are planning to manipulate F4V/MP4/H264 and produce Flash Player 10 SWF. If this is your plan, do not forget to replace the existing FLVPlayback component in the library with the new one as well before upgrading your FLA to Flash CS4.Ddrag and drop the FLVPlayback on stage. You will be prompt to replace. Then save your FLA with Flash CS4. Doing so will guaranty better support of any new files extension supported by latest Flash Player and/or FLash Media Server. Enhancement are always likely to happen from one version of Flash CS to another. From there you will be on track for awesome new features.

Finally, I also recommend ActionScript 3 devs to use load method as much as possible and avoid source in AS3 CS3 code. Sanity check your code if you don't want to upgrade to latest FLVPlayback but still want to manipulate MP4/H264/F4V file by just targeting Flash Player 10.

BTW: If you are manipulating FLV, you are just fine.