Archive for April, 2007

AS 3 to FMS 2.0 101: objectEncoding

April 20, 2007

The way of handling videos has been changed a bit on AS3/FP9 as opposed to previously. Here are some basic notes:

1. NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0 (see note below for details);

2. It’s crutial to listen to/handle “NetStatusEvent” and before playing the video:

nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);

The handler waits for evt.info.code == "NetConnection.Connect.Success" before calling netStream/video, etc. and subsequent actions. If you don’t wrap these actions within onNetStatus handler and just call them right after nc.connect(url), the complier will throw the following error:

ArgumentError: Error #2126: NetConnection object must be connected.
at flash.net::NetStream/flash.net:NetStream::construct()
at flash.net::NetStream$iinit()
at video_AS3_02_fla::MainTimeline/video_AS3_02_fla::frame1()

So it’s basically 2-step process to code for playing prerecorded videos in FMS2/FP9.

3. Both “rtmp:/test_streams/” and “rtmp://localhost/test_streams/” work if streaming from the same machine;

4. The videos are under “Flash Media Server 2\applications\test_streams\streams\_definst_”

More about “ObjectEncoding”:
When using AS 3 in conjunction with Flash Media Server 2 (which was released prior to AS 3), it’s crucial to set “ObjectEncoding” property of the NetConnection instance or class to “AMF0” (encoding for ActionScript 1_2) using the following code; otherwise, a netconnection will fail (NetStatusEvent.info.code: “NetConnection.Connect.Failed”/NetStatusEvent.info.description:”objectEncoding error”). It can be either a class property or per instance base:

NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0;

or

nc.defaultObjectEncoding = ObjectEncoding.AMF0;

The following code snippets show how to play a prerecorded flv stream from FMS 2:

This is a basic two-step process that is needed to play flv

package {
import flash.display.Sprite;
import flash.net.NetConnection;
import flash.net.ObjectEncoding;
import flash.events.Event;
import flash.events.NetStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.events.AsyncErrorEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.net.NetStream;
import flash.media.Video;

public class StreamTest extends Sprite
{
private var appURL:String = "rtmp://localhost/test_streams/";
private var nc:NetConnection;
private var trcTxt:TextField;
private var trctxtFmt:TextFormat;

public function StreamTest()
{
init();
}
private function init():void{
trcTxt = new TextField();
trcTxt.border = true;
trcTxt.wordWrap = true;
trcTxt.autoSize = TextFieldAutoSize.LEFT;
trcTxt.width = 400;
trcTxt.height = 30;
trctxtFmt = new TextFormat();
trctxtFmt.font = "Verdana";
trctxtFmt.size = 8;
trcTxt.defaultTextFormat = trctxtFmt;

addChild(trcTxt);
//need to set to AS2
NetConnection.defaultObjectEncoding = ObjectEncoding.AMF0;

nc = new NetConnection();
//nc.client = new CustomClient();
nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
nc.connect(appURL);
}
private function connectStream():void{
var ns:NetStream = new NetStream(nc);
//ns.client = new CustomClient();
var vid:Video = new Video();
vid.attachNetStream(ns);
//this works
//var url:String = "http://www.helpexamples.com/flash/video/cuepoints.flv";
//this doesn't work
//var url:String = "powell.flv";
//this works
//var url:String = "flv:powell";
//this works, too!
var url:String = "powell";
ns.play(url, 0, -1, false);
addChild(vid);
trcTxt.text = vid.toString();
}
private function onNetStatus(evt:NetStatusEvent):void{
switch(evt.info.code){
case "NetConnection.Connect.Success":
trcTxt.text = evt.info.code;
connectStream();
break;
case "NetConnection.Connect.Failed":
trcTxt.text = evt.info.code;
break;
case "NetStream.Play.StreamNotFound":
trcTxt.text = "not found";
break;
}
}
private function onSecurityError(evt:SecurityErrorEvent):void{
trcTxt.text = evt.toString();
}
private function onAsyncError(evt:AsyncErrorEvent):void{
trcTxt.text = evt.toString();
}
}
//class CustomClient{
//public function onMetaData(info:Object):void{
//trace("metadata: duration="+info.duration+" width="+info.width+"height="+info.height+" framerate="+info.framerate);
//}
//public function onCuePoint(info:Object):void{
//trace("cuepoint: time="+info.time+" name="+info.name+" type="+info.type);
//}
//}
}

Advertisements

Remote SharedObject 101: Take one|”sharedball”

April 12, 2007

/*
* The position of the sharedball can be updated by client or by other clients.
When the client updates the sharedball position, simply render and display the ball. The client also needs
to update the Model (RSO) and the Model will broadcast all the changes via “onSync” events to other clients that is connected to the Model;
The updates from other clients are accomplished by RSO “onSync” handler.
*/

var sharedBall_mc;
var nc = new NetConnection();
var rso;

nc.onStatus = function(info){
switch(info.code){
case “NetConnection.Connect.Success”:
rso = SharedObject.getRemote(“position”, nc.uri);
rso.onSync = function(list){
for(var i in list){
var info = list[i];
updateMC();
}
}
rso.connect(nc);
break;
}
}

sharedBall_mc.onPress = function(){
this.startDrag();
this.onMouseMove = function(){
updateModelBy(this);
}
};
sharedBall_mc.onRelease = sharedBall_mc.onReleaseOutside= function(){
this.stopDrag();
delete this.onMouseMove;
}
function updateModelBy(mc){
rso.data.ball_x = mc._x;
rso.data.ball_y = mc._y;
}

function updateMC(){
sharedBall_mc._x = rso.data.ball_x;
sharedBall_mc._y = rso.data.ball_y;
}

nc.connect(“rtmp:/tutorial_sharedball”, false);

destroy (A.K.A. gabage collect) a movieclip/textfield

April 9, 2007

First of all, in order to free memory, any reference to the instance
needs to be deleted.

Secondly, removeMovieClip() will remove a MovieClip instance from Stage and removeTextField() will remove a TextField instance from Stage.

var tn:MovieClip = this.createEmptyMovieClip(“tn”, 0);
var tn_nested:MovieClip = tn.createEmptyMovieClip(“tnNested”, 0);
var tf_nested:TextField = tn.createTextField(“tf”, 1, 0, 100, 100, 100);
tf_nested.text = “hello world!”;
tn.loadMovie(“http://assets0.twitter.com/images/twitter.png?1175908827“);

destroy_btn.onRelease = function(){
tf_nested.removeTextField();

tn.removeMovieClip();

trace(“is tn instanceof MovieClip after removeMovieClip: “+(tn
instanceof MovieClip));//false
trace(“is tn instanceof Object after removeMovieClip: “+(tn
instanceof Object));//false
trace(“tn type after removeMovieClip: “+ typeof(tn));//movieclip
trace(“is tf_nested instanceof Object after removeMovieClip:
“+(tf_nested instanceof Object));//false
trace(“tf_nested type after removeMovieClip: “+(typeof(tf_nested)));/

/movieclip
trace(“tn is “+tn+”; tf_nested is “+tf_nested);//tn is ; tf_nested is

delete tf_nested;
delete tn;

trace(newline+”>>>>delete tn>>>>”);
trace(“tn after destroy: “+(tn instanceof MovieClip));
trace(“tn after destroy: “+(tn instanceof Object));
trace(“tn type after destroy: “+ typeof(tn));
trace(“tf_nested type after destroy: “+(typeof(tf_nested)));
}

 

The code above first calls removeMovieClip()/removeTextField() first to remove the instances in question and trace down and delete all their references to completely destruct them for garbage collection.

 

BTW,  instanceof MovieClip will return false after “removeMovieClip” is invoked on an mc while typeof(mc) will still return “movieclip”.

“COUNT”, group by” and “having”

April 1, 2007

To find out the total number of rows in the table:

SELECT COUNT(*) FROM blog_articles;

or (“blogID” being the primary key):

"SELECT COUNT(blogID) from blog_articles";

The differences between COUNT(*) and COUNT(col_name) are:

1. COUNT (*) and COUNT(col_name) will NOT necessarily return the same result. COUNT(col_name) will NOT return NULL rows, while COUNT(*) will;

2. Performance wise, there is a big difference as COUNT(*) is read from table info, while COUNT(col) really counts the rows. So COUNT(*) would be faster.

To find out if there are stories with different url sharing the same headline (“title”):

"SELECT * FROM blog_articles GROUP BY title HAVING COUNT(url)>1;"

To find out the total number of different headlines(“title”):

"select count(title) as count from (select title from blog_articles group by title) t;"