as3: 2008年7月アーカイブ

一部更新、追加があったのでdocsも更新しときました。
といっても、このライブラリ使ってんの僕だけだったりして。

Utils
http://www.libspark.org/browser/as3/Utils/src/org/libspark/utils

asdocs
http://www.libspark.org/htdocs/as3/utils/

ダウンロード
http://www.libspark.org/svn/as3/Utils/docs/utils_docs.zip

是非挑戦してみてください。
先攻・後攻は「SETTING」ボタンから変更できます。


ルール
  • 同じ行なら何個でも取れます。
  • 間を飛ばして取ることはできません。
  • 最後の1つになったら負け


FlashDeverop + FlexSDK で作ってます。
Flash IDE は今回使ってません。
FlexSDK だと、書き出しが早くてすばらしいですね。

AS3 で FLV のメタデータの取り方が分からずに、かなり無駄に時間を費やしてしまった。。。
FLV のメタデータは NetStream から onMetaData を使って取得できるんだけども、
この onMetaData の使い方がさっぱり分からなかったので忘れないようにメモ。
経過があまりにもアホくさすぎて絶対忘れないけども。

ビデオメタデータの使用
NetStreamオブジェクトの client プロパティを指定して、
指定したオブジェクトに onMetaData メソッドを定義しておくと使える。

この client プロパティの存在に気づかずに四苦八苦してた自分が情けない。

挙句の果てに、ここ見て自前で ByteArray からメタデータ取ろうとしてしまった。

ByteArray から取得した FLV の値を出力した一例。
// FLV Header
Signature = FLV
Version = 1
Flags = 5
Offset = 9

// FLV Stream
PreviousTagSize = 0

// FLV Tag
Type = 18
BodyLength = 224
Timestamp = 0
TimestampExtended = 0
StreamId = 0

// MetaData
videodatarate = 1000
audiocodecid = 2
canSeekToEnd = true
duration = 8.866
audiodatarate = 128
framerate = 30
width = 450
videocodecid = 4
height = 400
audiodelay = 0.038

アホですよ。まったく。

ここまでやって、ちゃんと取得できることに気づいた。
そもそも何で AS3 なのに NetStream はこんな実装なんだ。
腹立たしい。アホか!

一応以下にソース残しときます。
結果的に中途半端なものになってますが、
なんか消してしまうのも勿体ない気がしてしまって。(費やした時間が。)

public function readFLV(data:ByteArray):void
{
    // FLV Header
    var Signature:String = data.readUTFBytes(3);
    var Version:uint = uint8(data);
    var Flags:uint = uint8(data);
    var Offset:uint = uint32(data);
    
    // FLV Stream
    var PreviousTagSize:uint = uint32(data);
    
    // FLV Tag
    var Type:uint = uint8(data);
    var BodyLength:uint = uint24(data);
    var Timestamp:uint = uint24(data);
    var TimestampExtended:uint = uint8(data);
    var StreamId:uint = uint24(data);
    var Body:ByteArray = new ByteArray();
    data.readBytes(Body, 0, BodyLength);
    
    
    // Body(FLV Tag Type = 0x12 : AMF)
    var a:uint = uint8(Body);// ???
    var b:uint = uint8(Body);// ???
    
    // MetaData
    readString(Body);
    var metadata:Object = readMixedArray(Body);
    
    
    trace(Signature, Version, Flags, Offset);
    trace(PreviousTagSize);
    trace(Type, BodyLength, Timestamp, TimestampExtended, StreamId);
    
    // MetaData の中身
    for (var val:String in metadata) {
        trace(val + "=" + metadata[val]);
    }
    
}

public function  uint8(data:ByteArray):uint { return data.readByte(); }
public function uint16(data:ByteArray):uint { return data.readUnsignedShort(); }
public function uint24(data:ByteArray):uint { return data[data.position++]<<16 | data[data.position++]<<8 | data[data.position++]; }
public function uint32(data:ByteArray):uint { return data.readUnsignedInt(); }

public function readNumber(data:ByteArray):Number
{
    return data.readDouble();
}
public function readBoolean(data:ByteArray):Boolean
{
    return data.readByte() == 0x01;
}
public function readString(data:ByteArray):String
{
    var len:uint = data.readByte();
    return data.readUTFBytes(len);
}
public function readObject(data:ByteArray):Object
{
    return null;
}
public function readMixedArray(data:ByteArray):Object
{
    data.readByte();
    var length:uint = data.readInt();
    var res:Object = { };
    var value:*;
    var name:String;
    var type:uint;
    var len:uint = data.length;
    for (;; ) {
        var separator:uint = data.readByte();
        name = readString(data);
        type = data.readByte();
        
        if (type == 0x09) break;
        
        switch(type) {
            case 0x00 : { value = readNumber(data); break; } // Object
            case 0x01 : { value = readBoolean(data); break; } // Object
            case 0x02 : { value = readString(data); break; } // Object
            case 0x03 : { value = readObject(data); break; } // Object
            //case 0x04 : { break; } // Movie Clip
            case 0x05 : { value = null; break; } // Object
            case 0x06 : { value = undefined; break; } // Object
            //case 0x07 : { break; } // Reference
            case 0x08 : { value = readMixedArray(data); break; } // MixedArray
            case 0x0a : { value = readArray(data); break; } // Array
            case 0x0b : { value = readDate(data); break; } // Date
        }
        res[name] = value;
    }
    return res;
}
public function readArray(data:ByteArray):Array
{
    return null;
}
public function readDate(data:ByteArray):String
{
    return null;
}
Spark Project の Utils ライブラリの ASDoc を書き出してアップしてみました。
HTMLでアップするとファイルが多いのでZIPに圧縮してます。

あとちょろちょろとクラスファイルを足してます。
何か無駄なところも多々あると思います。
実装が微妙なところも結構あります。EventUtil とか。

Utils
http://www.libspark.org/browser/as3/Utils/src/org/libspark/utils

utils_docs.zip
http://www.libspark.org/svn/as3/Utils/docs/utils_docs.zip


とりあえず、今こんなのが入ってるってのが把握できればと思います。

今までまったく気づかなかったことなんですが
addEventListener("enterFrame", handler);
function handler():void {}
ってすると
ArgumentError: Error #1063: _fla::MainTimeline/handler() の引数の数が一致していません。0 が必要ですが、1 が指定されました。
ってエラーが出て怒られるんだけども、
addEventListener("enterFrame", handler);
function handler():void { arguments; }
上記の場合はそのまま何事もなく実行される。
上記のようにイベントハンドラの中に「arguments」が入ってると、引数は別に定義されてなくてもいいみたい。

これは引数の数は関係ないみたいだけども、「...rest」が入ってると「arguments」が使えなくなるのでダメっぽい。
まあ、そもそも「...rest」入れてる時点で引数の数はあんまり関係なくなるけども。

じゃあ、普通に関数でも使えるかと思って試してみた。
function test():void {arguments;}
test(1, 2, 3);
普通に怒られた。
引数の数が正しくありません。0個以下であることが必要です。
って。
で少し呼び出し方を変えてみる。
function test():void {arguments;}
test.apply(null, [1, 2, 3]);
と、今度はすんなり通った。
ようはイベントの通知には apply が使われてるってことか。

もしかして dispatchEvent もこの要領で「dispatchEvent.apply」とかすれば引数勝手に増やせるかも?
とか思ったけど、やっぱりそれはダメでした。

で、結局のところ「だから何なんだ」って話しで、
特に何も得することもないんですが。


通常、外部からの呼び出しの時は引数無しだったり、個定数の引数を渡さないといけなくしておいて
内部処理のみ、内緒でこっそり引数渡してやりたい時なんかは使えるかもしれないですね。
再起処理の時のフラグとか。