2012年9月25日、株式会社ディー・エヌ・エー セミナールームにて、「 SWF研究会#2@東京」が開催されました。
今回は、AdobeのモバイルFlashのプラグインが正式に提供終了を迎える背景より、これらを利用していたエンジニアが集結し、現状の問題点や、今後の技術転向など熱く強く共有する場となりました。
また、事前に目的も以下の様に告知しており、意識の高さが伺える勉強会となりました。
SWFの構造、情報要素や、その解釈についての知識を共有するのが目的です。一通り聞いて理解すれば、簡単なFlash Playerが自作出来る位の内容を目指します。
参考URL
タイムマップは以下の通りです。
19:00:発表
@yoya:SWFの情報要素とバイナリの読み方
@ken39arg:Shapeの基礎の基礎
@kohei_april20:アクションスクリプト実行処理系
@tkihira:Flash Runtime Engineの実装
21:00:懇親会&LT
@y_imaya:JavaScriptによるLossless画像の扱い方
@a_bicky:アフィン変換とgetTransform(仮)
@rakusan:フォントとテキスト
@akb7_jp:SWFファイルの覗き方
@flarephoenix:ミニマムswfエンジン for iOS
@fchiba:Shape Morphing 解説
まずはじめに、DeNA紀平氏より開催のご挨拶として、「 本勉強会を企画したときは、こんなにもたくさんの人がFlashPlayerを作りたいとは思わなかった」と切り出し「明日からオープンソースのFlashPlayerがタケノコの様に発表されると思います」と会場の笑いを誘い、始まりました。
SWFの情報要素とバイナリの読み方
まず始めに本勉強会主催の一人でもあるよや氏(@yoya)より、「 SWFの情報要素とバイナリの読み方」についてお話がありました。
よや氏
自己紹介では「六本木の方から来た」「 青色のポロシャツに見た事のあるロゴマーク」などから「会社名は察してください。今日はアウェイながら頑張ります」と和やかなムードの中本題に入ったよや氏。今回の発表では、SWFフォーマット(バイナリ)の読み方のコツに関して、わかりやすい資料を元に説明いただきました。
SWFを触る目的
そもそもなぜSWFを触らなければならないのか? それは、とくにモバイル向けサービスをよりリッチにするためです。そのため、FlashLiteのスペック(制限)を超えるべくさまざまな対応を行い、以下のように整理していました。
最大100KB→最小限のデータをSWFに載せる
実行引数を渡せない→SWFにパラメータ値を埋め込もう
画像を動的に入れ替えし辛い→SWFの画像も入れ替えてしまえ
これらを対応していた結果、エンジニアが「まさかの実行ファイル(SWF)動的生成」というスキルを身につけます。さらにに時は流れ、現在はスマートフォン時代になり、
iOSにFlashPlayerが無い→JavaScriptでSWFを解釈して何か表示
Androidも4.1からFlashPlayerがない→じゃぁ、こっちも!
と、エンジニアが「まさかのFlashPlayer実装」を行うという流れになりました。
これらを達成するために、SWFを理解し触らなければならない、と説明しました。
SWFの仕様
Adobe社より提供されている公式仕様書 は、( データ形式の正確さはさておき)詳細に書かれているものの、意味に関する記述は不足しています。仕様書以上の情報については自力で調べたり、仕様書から察したりするしかなく、この辺りはFlashエンジニアの泣かせどころだと言います。
SWFの構造
実際にFlashのバイナリを解釈する上で、その構造を理解する必要があり、本講演では、それぞれの構造について詳細に説明がありました。
SWFの基本的な構造は全てヘッダとタグで構成されているとし、SWF Header、SWF Header FrameSize、SWF Tag example、SWF Tag type(仕様書のappendix Bをおすすめ) 、SWF Tag Categories、SWF Tag formatなどから、ShowFrame,END、SetBackgroundColor、DefineBitsJPEG 、DefineBitsLossless (パレット、RGBA) 、DefineShape 、PlaceObject、MATRIX、CXFORMなどに関するTagフォーマット、バイナリの読み方などをそれぞれのケースに応じて説明しました。詳細の内容は資料を参考にしてください。
Shapeの基礎の基礎
続きまして、カヤックの荒賀氏より「Shapeの基礎の基礎」についてお話がありました。
カヤック 荒賀氏
Shapeの基礎の基礎
http://ken39arg.github.com/swfstudy/#1
「簡単な1フレームのSWFをベクターデータとして再現できるようになる」事を目標とし、初~中級者を対象に非常にわかりやすく説明いただきました。
SWFのベクター表現
ベクター描画を実現するのは以下の3点のみといいます。
moveTo() ポイントの移動
lineTo() 直線を引く
curveTo() 二次ベジェ曲線
これらを実際に利用して正方形、円を記述する方法についてソースコードと共に説明し、この3点があればどんな言語にも必ずコンバートできると断言。デモでは実際に円と三角形を組み合わせた(トイレのシンボル)を用いて実際に(swfdump、ActionScript3.0、JavaScriptへ)コンバートする過程が紹介されました。
Shapeの詳解
次にShapeタグの種類、DefineShape*タグの構造 、FillStyle(塗り) 、LineStyle(線、太さ、色) 、ShapeRecordの説明があり、実際に正方形のタグを例にとって「パスは相対値、座標は1px=20で表す整数値」「 fillスタイルのインデックスは0ではなく1から始まる」「 curveToでは少々複雑なので注意が必要」などといった経験も交えた解説が行われました。
また図形の再現として、異なる色の2つの画像の重なる部分の色が混ざっている図の作例で、swfDumpでは奇麗に2つの図形、2つの色+図形が重なる部分の色も重なり3色となるのに、ActionScriptでは同じように記載しても重なった部分が消えてしまう事例がありました。
この場合はfillStyle0とfillStyle1の両方にStyleが設定されている事を再認識し、それらを踏まえて再度書き直し、問題なく表現できたとのことです。
しかしながら、実際には1レイヤだけのswfなどほとんど存在せず、複数のShapeを組み合わせて利用することがほとんどであり、これらのShapeを配置するためにSpriteとルートオブジェクトが持っているのがPlaceObjectであると解説しました。またこれに関連して、基本的な配置、ベクターをActionScriptにする例などの説明がありました。詳細はスライド資料 にまとまっておりますので、ご参照いただければと思います。
簡単なSWFをSVGにコンバートしてみよう
最後に簡単なSWFをSVGにコンバートする説明として、「 SVGのタグ(スライド)さえ知っておけば最低限の事は簡単にできる」と対象SVGのタグの説明と実際にコンバートした結果を説明して締めくくりました。
アクションスクリプト実行処理系
続いて、株式会社サイバーエージェントの森野浩平氏より、アクションスクリプト実行処理系と題した、SWFにおけるアクション、アクションのデータ構造、アクションモデル、実装にあたってのハマりどころについてのお話がありました。
森野氏
最初にアニメーション基本要素として、各タグの説明がありました。パラパラ漫画+アクションとして、以下のようなものがあります。
DoAction
syowフレーム時に実行されるもので、ヘッダの後にアクションが並び、最後にアクションエンドがある。
DefineButton
ボタンの定義タグ、ボタンへのイベントにより実行されるアクションを持つ。
DefineButton2
拡張版、コンディション(発動条件)それに結ばれるアクションで構成される。
ACTIONRECORD
ActionCodeによる命令とパラメータ。ActionCodeごとにpayloadの読み方が決められている。パラメータを必要とする命令は0x80以上でpayloadのレングスがあり、その後可変長のデータが入ってくる。
また、アクションモデルの説明として、データを読み取った後にどのようにアクションをするかがアクションモデルであり、アクションは幾つか存在し、それが混在していると説明します。たとえばSWF3アクションはムービーをはじめたり、止めたり、URL取得したりできますが、これだけでは複雑なプログラムは組めないため、SWF4アクションを利用することにより、式の評価、条件分岐、ループができるようになります。なお、これらは仮想スタックマシンによって実現されていると説明がありました。
実際に体験したこと
Flashプレーヤーを実装して経験したこととして、仕様書にない「謎のアクション0x2D」に遭遇し、調査したところ、fscommand2()(デバイスの情報取得をするもの)だったという経験談が披露されました。
こうしたFlashプレーヤーを実装して仕様がよくわからなくハマりどころとして「実行順序」「 実行タイミング」「 プロパティ変更後のレンダリング」などが挙げられ、これらに対しては、「 本家Adobeの挙動をよく見てテストケースSWFを作成」したり「フレームレートを下げてみて実行」するなど、いかに仮説をたてて、実装、検証を繰り返すかがキーとなると説明がありました。
Flash Runtime Engineの実装
発表枠の最後は、株式会社ディー・エヌ・エー紀平氏より「Flash Runtime Engineの実装」についてお話を頂きました。
紀平氏
実際に利用した資料の公開はないものの、当日行われたUSTREAMが公開されているうちは実際の説明とともに視聴することをお勧めします。
Video streaming by Ustream
実は本勉強会、先の3名に講演いただいた内容が「バイナリのパース(読み方) 」 「 シェイプの詳解とSVG変換」「 アクションスクリプト実行処理系」で、これらを組み合わせて動かすエンジンを作成すれば、FlashPlayerができる、と今回の勉強会の順序自体に大きな意味が隠されていると話し、エンジンの実装=いわゆるメインループの実装であると切り出しました。
FlashPlayerにおけるメインループとは
タイムラインを1つ動かす
バーチャルマシンを動かす
持っているデータを描画する
これを秒間何回も動かすことです。実際の所、これだけで終わりではあるものの、これらを自力で実装するには非常に難易度が高い(全てがラスボス級)と話しました。
ライムラインとはFlashの時間軸
まず、説明用に簡単な30フレームのタイムラインにて、それぞれのフレームでどのようなことが行われているかについて説明がありました。
Frame 動作
1 初期シェイプの配置アクションの実行
DefineShape
PlaceObject
PlaceObject
DoAction
ShowFrame
2~9 ShowFrame×8
10 新しいシェイプ・MCの追加
DefineShape
PlaceObject
ShowFrame
Frame 動作
1 それぞれの動作
4 それぞれの動作
6 それぞれの動作
13 それぞれの動作
16 それぞれの動作
11~19 ShowFrame×9
20 シェイプの削除
PlaceObject
RemoveObject
ShowFrame
21~29 ShowFrame×9
30 最終フレーム
ShowFrame
End
またこのとき、エンジンでの処理としてはDisplay Listに沿って描画する。無駄なリソースは持たず、たとえば同じ画像は1つのものを複数箇所へ描画して対応すると説明がありました。
タイムライン
それまでの講演で複数の方々から説明があった通り、タイムラインには幾つか困った問題もあり、主に処理(実行)順序の問題を指摘しました。
実際に先に説明したタイムラインを用い、どのようにタイムラインを処理するかと投げかけ、
フレーム10ではA → B
フレーム11ではB → A
と突然変わってしまい、しかも公式ドキュメントにもないので、結果エンジニアが検証しながら試すしかないと指摘していました。
バーチャルマシンの実行の基礎
タイムラインの処理時に、そのフレームで必要なアクションスクリプトの順序を記憶し、キューの先頭から実行…というわけにも行かず、いろいろと問題がある点を説明しました。このあたりも試行錯誤で試していくことが求められていると言います。
VMの落とし穴
callとgotoFrameが存在し、callはその場で指定されたframeのスクリプトを呼び出し、call(4)と記述すれば4フレーム目のスクリプトを呼び出します。一方gotoFrameが実行されると、現在のカレントフレームを新しいフレームに即時変更、新しいフレームに付随するアクションスクリプトをキューの最後に追加、そのまま残りのスクリプトを実行します。すなわち、カレントフレームが思っていた場所と変わってしまうため注意が必要と指摘しました。
その他泣き所
その他の問題として、「 数値、文字列両方が混在」「 部分的に大文字小文字を判断したり(しなかったり)する」「 基本正常系のドキュメントしかなく、失敗時の挙動似ついては仕様書が公開されていない」「 リードオンリーのプロパティのサンプルプログラムで代入している(!) 」など、非常に苦労する部分が多いと説明がありましたが、一番の問題としては、( 仕方なくではあるものの)世の中の大部分のFlashエンジニアはFlashPlayerの異常系やバグ挙動を平然と利用してコンテンツを作っていることが多く「バグまで実装しないといけない。」と指摘がありました。
最後に、公式な資料、公開された仕様などが曖昧な部分に問題は多いと指摘し、取り組むエンジニアは心を強く持って取り組んでほしいとする一方で、「 ActionScriptを扱わない」「 クリッピングやモーフィングや着色などを扱わない」などと割り切った簡易FlashPlayerであれば、結構簡単にできるのも事実であり、興味があればぜひとも挑戦してほしいと締めくくりました。
懇親会&LT
第二部として、立食形式の懇親会を行いながら簡単なLTを実施しました。非常に有益な情報も多く、参加者の関心も高かったため、可能な限り、発表者、資料を公開させていただきます(ご協力いただきました皆様、ありがとうございました) 。
JavaScriptによる Lossless 画像の扱い方:@y_imaya
HTML5 Canvasで学ぶアフィン変換:@a_bicky
フォントとテキスト:@rakusan
SWFファイルの覗き方:@akb7_jp
ミニマムswfエンジン for iOS:@flarephoenix
Shape Morphing 解説:@fchiba
おわりに
今回、主にモバイル向けFlashのエンジニアが、すでに終焉がささやかれる技術をどうするといったネガティブな方向ではなく、限られたリソース、技術的制限の中で最高のパフォーマンスを求める非常にストイックなエンジニアが集まり、それぞれが実際に苦労した点、トライした事を発表し合う場になったと感じました。実際、このテーマでこれだけの人たちが発表するという熱意がすべてを物語っており、また、会社や提供しているサービスなどは関係なく、同じ苦労を乗り越えた同志のようにも見えました。
また、取材許可、写真、資料の公開も快諾していただき、筆者はエンジニアでも分野が異なりはするものの非常に得るものが多い勉強会でした。次回は時期こそ未定とのことですが、開催は前向きに検討しているとのことですので引き続き注目していきたいと思います。