KLab若手エンジニアの これなぁに?

KLab株式会社の若手エンジニアによる技術ブログです。phpやRubyなどの汎用LLやJavaScript/actionScript等のクライアントサイドの内容、MySQL等のデータベース、その他フレームワークまで幅広く面白い情報を発信します。

Android

FlashLiteなコンテンツをHTML5に移植してスマートフォンでも見れるようにした

太平洋高気圧はもうちょっと手加減してくれてもいいかな、って思うんですけど、やっぱり農作物なんかにはこの気温が必要なんでしょうか。 osuga-hです。 ガラケーWEBでリッチコンテンツの要FlashLite。これまでソーシャルゲームではFlashLiteがゲーム演出の要でした。 ところが時代はスマートフォン。各社ソーシャルゲームプラットフォームが一勢にスマートフォン用プラットフォームを公開してからそこそこ時間も経過しました。 そこにプラットフォームがあるならゲームを出さねばなるまい!!! そんなわけでこそこそFlashLiteコンテンツをHTMLやらJSやらCSSに移植していたのですが、コレがもう全くノウハウにならない感覚作業のオンパレードで他人に伝承できない。 なんとかならんのか?! そこで取り合えず既存のFlashLiteコンテンツをスマートフォン用にHTML5対応したときのログを公開してみようと思います。 何回かに分ける予定で、今回は作業の全体像に関して言及していきます。

FlashをHTML5にする作業の流れ

そんなこんなで今回は全体の流れを紹介してみたいと思います。 いずれの項目も決定版というより、いくつかやってきて取り合えずこれで落ち着いて来た、という内容になっています。 なんとか改善できるところはないのか?自動化出来ないかというのは並行して模索中です。

前提

移植作業はそれまでのFlashコンテンツの作成方法や、動的合成の有無でまったく別のアプローチが必要になると思います。 ここでは以下の条件下にあるFlashコンテンツの移植を扱います。
  1. FlashコンテンツはAdobe Flashを使って実装されている。Flexは使われていない。
  2. ロジック実装がされており、ボタンによる場面やUIの制御がActionScriptによって実装されている。
  3. ASのバージョンは1だったり2だったりする。
  4. 素材を元にSWFを動的に生成している

1. flaファイルを見ながら、素材のレイアウトをHTML+CSSで再現する

(オーサリングツールの方の)Flashを使って、レイアウトを移植していきます。 ActionScriptは取り合えず無視して、対象のflaファイル(Flashのソースファイル)のルートタイムライン※1上で重要なフレームのレイアウトをHTML上に再現していきます。 配置はflashと同様に絶対座標指定で行います。アニメーションは保留にして、バシバシ置いていきます。 この段階で画像素材もHTML用に切りだします※2。 作業コストは演出・素材点数に比例します。携帯コンテンツだとだいたい1日か長くても2日ぐらいじゃないでしょうか。 ※1 ルートというより実際にFlashを再生したときの見た目に近いタイムライン。 ※2 生の素材を使ってもいいのですが、Flash上で変形・着色などがされてる場合があるので、急ぐ場合はFlashから履き出してしまうのがいいでしょう。 スクリーンショットで切り出すのも有効だと思います。

2. JSにアニメとロジックを書いて行く

まずはASを読んでロジックを確認します。大抵の場合ほとんどがUI制御のためのコード※3なので、書きなおした方が早いです。 また細かいところはASを記述した人に確認を取って進めていきます。 同時にアニメ用のコードも埋めていきます。 Flash再生時の時系列に移植していくのがいいでしょう。 ここでも演出の多いFlashが相手だと多くの時間を取られます。 サーバーサイドでFlashの動的生成をしている場合は、テスト用のデータを貰えると作業が進めやすくなります。 この時の動作確認はPC上でSafariもしくはChromeでやります※4 。(Macの人はSafariで鉄板) ※3 ゲームの場合サーバサイドにゲームロジックがあることも少なくなく、その場合Flash側はログ再生してるだけということが多いです。Flashコンテンツ側でしっかりゲームロジックを持っている場合はこの限りではありません。 ※4 Android、iPhoneともデフォルトブラウザがWebkitなため。現状Firefox、Operaは無視しています。そのため、PC上での確認にSafari・Chromeが使えます。

3. 実機確認

PC上で動いたからといって実機で動くかというとそうは行きません。 Webkitだから同じでしょとか思っていると痛い目をみます。 アニメーションを追加するたびに実機確認するぐらい、頻繁に確認します。 この結果次第で演出を削ることも検討していきます。

4. サーバサイドとの繋ぎこみ

Flashを動的生成している場合、最後にサーバサイドとのつなぎ込みをします。 変数はjsonでHTML上に吐き出し、合成していた画像はhttp経由でダウンロード出来るようにします。

まとめと補足

今回は何らかのロジックが実装されているFlashLiteコンテンツをAdobe Flashで作成している場合の移植の流れを載せました。 条件によっては全く別のアプローチの方がいい場合もあるでしょう。例えば、先頭から再生して最後で止まるだけのFlashアニメーションならWallabyで自動変換したものに手を加える方が早く済むかもしれません。 またFlexなどスクリプトベースでつくっていればenchant.jsなども視野に入ってくると思います。

その他の参考文献

[斜め読み]Josh Tynjala「GridshockをFlashからHTML5へ移植してみた」 Flash→HTML5移植は本当か? ハンゲームの事例 もうFLASH不要かも? HTML5アニメ作成ソフト「Hype」登場 iOSにも対応! 【増田(@maskin)真樹】

Android 2.3 Only Hacks 書評 #2

このblogには久々の登場となります、nakazawa-k(@muo_jp)です。 最近はAndroid方面で変な電波を飛ばしたりしてます。ちなみに1日の自ツイート数が100を超えた日に「なんかもう帰れないとこまで来たのかな」と思った程度の真人間()です。 さて、今回はレビュー(※1)を行ったご縁で献本を頂きました「Android 2.3 Only Hacks」の書評をかいてみます。といっても内容についてはきっと他の方が書いてくださる(maruyama-rさんも書いてくれてる)ので、私は「どういう人が、どういう風にこの本を読んで、読んだその次はこうしていくといいんじゃないかなー」という、なかなか押し付けがましいエントリを書いてみます。あんまり書評じゃない気がしますね、気にしないようにしましょう。 その前にこの本が他の本から飛び抜けているポイントをひとつ挙げてみます。 ・表紙がいい。ジンジャーブレッドマンの癒しっぷりはとても良い。 通常Android本といえばカバーが緑色でなんとなくドロイド君な感じのするものが多かったりします。これはAndroidのバージョンアップ頻度を考えると結構理にかなっていて、バージョン依存のものを紙媒体で出すとすぐに風化して賞味期限が大変短くなってしまう、という問題への対処と考えられます。けどこの本は「2.3で何が変わったか、何が出来るか」を解説するものなので、そんなこと気にせずアグレッシブにやった感がすがすがしくてとても好感を持てます(他の本をdisってるわけでなく、ただただ仕方ないということです)。 さて。 どういう人のための本か 冒頭にも書かれているように、この本は「Android自体に関する知識や開発経験は既にある程度持っているけれど最近のSDKを追いかけてはいない。何が出来るのか気になっているけどまとまって勉強する時間を取るのは大変だし日本語ドキュメントはあちこちに散逸してるしあばばばば」な方向けかな、と思います。記載されている情報の多くは既に(著者の方々も含め)いくつかのblogにて日本語情報として発信されているものでありますし、それこそ本書でターゲットとしているSDK(2.3系)の初期リリースからは半年近くの時間が経っています。それでも書籍としてまとまって出版されることには参照性と学習の面で多くの意味があるのだと、私は思います。「最近Androidから離れてたけど、なんか面白い機能追加されてるみたいだしこの機に勉強してみよう」なんてのも素敵ですね! この本の読み方 1. ざっと技術の流れを概観する。 OS/プラットフォームとして完成度が高まってきているAndroidにおいて、なぜこれらのAPIがサポートされたか、ということを考えながらアップデート全体を俯瞰してみるのは有用だと感じました。APIは無駄に追加されているわけでなく、何かしらデベロッパによる要求やGoogle(またはその他OHA参加者)が「こういう風に使って欲しい」という希望を持って追加されているものです。それをどのように解釈してアプリケーションに盛り込むか、というのはもちろんデベロッパそれぞれだと思いますが、ある時期にまとめて投入された新機能(とりわけ未完成なのになぜか先行投入されたOBBなど)を見て「これらのAPIを使える端末が普通に溢れてる未来(または現在)で、これらを活かしてどんなアプリやサービスを書くとユーザはもっと便利になり、嬉しくなるんだろう」と考えてみるだけでもなかなかワクワクします。 2. 機能を実際に利用する上でのヒントを本文から見つけ出す。 本書の各章を書かれた方々は、新SDKがリリースされてワクワクしながらドキュメントを読み、サンプルを読んだり動かしたりし、そして時にはうまく動かないその理由をAndroidのソースコードまで降りて調べてきて本書の執筆に至っています。速報的にその一部始終をtwitterやblogで発信されている方も多く居られますが、それらが書籍の中の1章として再構成されたことで「このAPIを使ってハマるところ」といった情報も全体にうまく織り込まれているように感じました。実際にAPIを使ってアプリを書いてみてなぜかうまくいかずハマる、という際に本書を開いてみるとヒントになるところがあるのではないかなぁ、と思うのですが今のところ実体験はしていないのであくまで推測ですはい。 3. ソースにアクセスして動かしてみたり読んだりする。 本書の価値の1/3ぐらいは、サポートサイトにて公開されるソースコード群にあるかな、と感じました。例えばBluetoothの項でInsecure通信(事前のペアリング無しに非暗号化通信を行うことが出来る)がサポートされたこととそのAPIに関する記載は行われていますが、書かれてるのは「従来のAPIのここを変えればInsecure通信出来るよ」ということだけなので、ぶっちゃけ「俺は以前にAndroidでBluetooth通信やってみたことあるぜ」という方以外にはスパルタンな記述です。けれど、サポートサイトにある実際のソースコードを読んで動かしてみることで、そこで使われているプログラミング手法を参考にしたり、関連するAPIの名前を手がかりとして更にドキュメントの山をひっくり返したり、と「実践してみて更に興味を持つ...」という好循環が生まれるのだと思います。なので、是非サポートサイトにアクセスしてソースをダウンロードしてみましょう。 ・この本を読んだ次は…! →デ部関連のイベントやメーリングリストに参加しましょう ご覧の通り、OSバージョンが上がると多くの新機能がサポートされます。そして、当然これからも同じくOSバージョンは上がっていきます。デベロッパ負担を減らすためにメジャーバージョンアップ間隔を広げる方向にはありますが、結果的にマイナーバージョン(2.3.2→2.3.3)ですらAPIレベル(Androidとして利用出来るAPIセットを定めた群)が変わるという状況になっていますし、タブレット向けのAndroid 3.xとそれ以外向けの2.xという2系統が当面は継続開発されており、基本的に3.xの新バージョンでの機能が2.xにバックポートされるという形を取るにしても既に状況は相当カオスです。 ということでデ部への参加をオススメします。新機能に敏感な方々が活発に情報交換を行っている、いいコミュニケーションの場と機能していると思います。関連イベントの開催地は多くが東京で、それ以外の地方のかたがちょくちょくリアル参加するのは難しいかと思いますが、大体Ustreamなどのライブ配信が行われるので、遠隔地からもだいぶ参加し易いと思います。 以上、書評といっていいのかよく分からない文章となりましたが参考頂けると幸いです。想定読者にマッチする方は買って損無いと思いますが、いくら本読んでもやっぱりAndroid系はアプリ(仕事でもプライベートでも)でアウトプットしてなんぼですよね(と自戒で締めくくる)。 ---- このblogエントリは、レビュー時の副産物としてEvernote内になぜか発生していた「全体的に非常によく調査した上で、更に執筆者自らがサンプル実装を行い動作を確認したコード、手法が掲載されており、旧バージョンのAndroidでの開発を行なってきた開発者が最新SDKを利用することでどのような利便性を得られるか、新たな機能を利用出来るか、という点がよく網羅されている。また、Gingerbread/Honeycombにて不完全ながらも提供されているAPI群を知ることで、Android自体が今後どのような進化の方向性を持っているか、という大枠での技術動向を掴むことも出来る。 惜しい点としては、著者が複数人であるためバージョン対応にばらつきが見られるところである。例えば、APIレベル11での追加サポート内容について具体的に言及している章とそうでないものが混在しており、本書が全体としてどのバージョンについてカバーしているか、という点が不明瞭となっている。これはいみじくもまえがきに記載されているように、本書執筆中にも複数のSDKがバージョンアップが行われたためであり、全ての品質を揃えることを優先するといつまで経っても出版出来ない、という事情を鑑みるとやむを得ないことと言える(特に想定読者は必ずしも最新SDKを追いかけてはいない開発者となっているため、完全な最新版対応へのコミットが大きく読者の利益につながるわけでもない)。 デ部関連イベントでの発表内容を追いかけることでその後の最新事情へ追随することは可能であるため、最新SDK動向への興味を強く持たれた読者においてはメーリングリストやイベントへの参加、著者blogの購読などで情報を継続的にアップデートされたい。」というメモをもとに書かれました。かための文章がお好みの方はこちらをどうぞ。 ※1: 押しかけレビューアで、最終確認用の版を頂いてそこに結構な量のtypo指摘を投げつけるという暴挙を行いました。多分編集さんは泣いてたと思います(面識ありませんが)

Android2.3で何が変わったんだろう?

はじめまして。若手ブログ初投稿のmaruyama-rです(twitter:@h13i32maru) 「Android2.3 - Gingerbreadをさくさく使うためのサンプルとテクニック - 」を本書レビュワーのnakazawa-kさんに貸していただいたので、僕が気になったところをピックアップして感想なんかを書いてみます。 まずこの本はAndroid2.3で追加/改善された機能の話なので今からAndroidを勉強しようとしている人向けというよりはある程度開発してきてAndroid2.3でどう変わったのかなーと気になってる人向けです。 各章は「機能の概要」と「実際のコード」で構成されています。なのでどんな機能が追加されたのかをさっと知りたい人は概要だけを、詳しく読んでみたい方はコードも合わせて読んでみるというのが良いと思います。 (僕は機能の概要だけをさらっと読んだ感じです) それでは僕が気になったところを書いていきます。

NFC

Android2.3でNFCに対応しました。NFCとはNear Field Communicationの略で近距離無線通信の規格だそうです(僕はこの本を読むまでぜんぜん知りませんでした)Android2.3ではこのNFCの規格に対応しており、NFCに対応した非接触ICカードから情報を受信したり送信したりできます。 NFCではNDEF(NFC Data Exchange Format)というNFCで使用するデータフォーマットが定義されています。このNDEFにはテキストを保持するのやURI保持するものなどいろいろあるようですが、それを解析するためのクラスは用意されていないようです。。ただAndroidSDK付属のNFCDemoにはそのサンプル実装があるので参考にすることができます。 注意としてはFeliCaはこのNDEFを使っていないので独自の実装が必要になるようです。 このNFCの章にのってるサンプルコードを理解するにはNFCの仕様をある程度しってないと難しいのかなという印象です(´・ω・`)でもNFC楽しそうですね!端末をさっとかざすだけでプロフィール交換やゲームのアイテム交換とかできそうですね!Suicaから乗車履歴をとってソーシャルゲーム等の進行に影響させたりもできるかも。

DownloadManager

大きなファイルをHTTP経由でダウンロードする場合に2.3から追加されたDownloadManagerを使うとすごく便利そうです。2.2以前なら自前でDefaultHttpClientなどを使って実装が必要だったことがDownloadManagerにお任せでできるようです。 ただ、中断やレジュームなどの処理方法が書かれていないのが残念です。developer.android.comのDownloadManagerを見ても中断やレジュームについては書かれていないようなので、まだ実装されていないのかも知れないです。。

Strict Mode

Strict Modeを使うとANR(Application Not Responding)の発生を開発者が検知しやすくなります。ANRとはユーザの入力に対し、アプリが何の応答もしないまま一定時間すぎてしまった状態をします。Androidでは「ユーザからの入力イベントの応答に5秒以上かかった場合」などに発生します。 Strict Modeを有効にするとANRが発生しそうな処理を実行するとエラーのダイアログやログを出力してアプリケーションを終了させることができます。これによりどこでANRが発生しそうなのかを開発者が知ることができます。 Strict ModeにはANRの検知対象を設定するためいくつかのポリシーがあります。ディスクの読み書きやネットワークアクセスなど開発者が自由にポリシーを設定することができます。 Strict Modeを有効にする方法は任意のActivityで以下のようなコードを実行します。このコード以降でStrict Modeが有効になるのでなるべく早い段階で有効にするほうが良いようです。

public void onCreate(Bundle savedInstanceState) {
  StricMode.enableDefaults();
super.onCreate(savedInstanceState);
}
それと注釈にあった「Honeycombからはメインスレッドでのネットワーク処理の実装はFatalとなり、コンパイル時に検知できるようになる予定です。」というのが凄く驚きです!思い切ったことをやるんだなと思いつつ、どうやってメインスレッドからの実行なのか判定してるのかも興味があるところです。 ユーザへ良いレスポンスを返すことにプログラム的に支援をしたり制限を加えることでAndroidアプリ全体の質を向上させることができると思うので、このStrict Modeは是非つかっていきたいですね。前述のDownloadManager、Service、AsyncTask、Thread/HandlerなどUIスレッド以外での処理方法がいくつも提供されているのでこれらを使えばそんなに難しくなくできると思います。

その他

  • OBB(Opaque Binary Blob)による暗号化ディスクイメージ
  • Native ActivityによるC/C++だけでのAndroidアプリ開発
  • Dalvik RuntimeのJIT改善とJRE6対応
  • Media Provider / Speech Recognitionによる音声のテキスト化
など面白い話がたくさん載っているのでAndroid2.3はどんな風に変わったのか気になっている方は是非読んでみることをお勧めします これを読むと2.3な端末がほしくなりますね(・∀・) おわり

Androidでかっこよくプレゼンしたい

はじめまして。fukaya-aと申します。
12/16から本日までインターンでKLabにお邪魔させていただいておりました。
恐れ多くも若手ブログに記事を書かせていただけるということで、ちょっと緊張しています。

さて、今回のインターンではかっこよくプレゼンするためのAndroidアプリを作りました。
私は普段研究の発表などでプレゼンをする機会がそれなりにあるのですが、
いろいろと不満点がありました。

・レーザーポインター、ストップウォッチなどを毎回準備しなければならないのが面倒
・操作のたびにPCの側にいなくてはいけない
・レーザーポインターがぶれまくる
調べてみると、こういう問題を解決するためのスマートフォン用リモコンアプリはそれなりに存在するようでしたが、
なかなか自分の欲しい機能をすべて揃えたものはありませんでした。
ということで、自分で作ることにしました。

<!--more-->
まず、自分が欲しいと思う機能は次の通りです。

・Bluetooth接続 : Wifi環境がなくても大丈夫なように
・スライド操作の方法が多彩 : ボタン、物理ボタン、加速度(ジェスチャー)
・クリック動作可能
・レーザーポインタ機能
・ストップウォッチ機能 : 指定時間で振動
ということで
bluetoothのRFCOMMのUUIDを探しまわったり、
解像度の違う端末の対応に苦労したりしましたが、
なんとか期間内に動くものを作ることが出来ました。

端末を振って次のスライドにということで、名前は安直にShakeNextとしました。
<div style="height:10px; clear:all;"></div>
<div align="center">

<img class="alignnone" title="icon" src="http://lh3.ggpht.com/_-cdXx9wc4dA/TRHHpilLARI/AAAAAAAAADw/wY07_zQLO3A/s144/next512.png" height="144" width="144">
</div>
<br />
<br />

アイコンはこんな感じです。
今思うともうちょっと作りこんでもよかった気もします…
<div style="height:10px; clear:all;"></div>
<div align="center">
<img class="alignnone" title="main" src="http://lh3.ggpht.com/_-cdXx9wc4dA/TRHHpvNniUI/AAAAAAAAAD0/Oo09PZKG3CQ/s144/main000.png" height="144" width="86">

</div>
<br />
<br />
メイン画面のキャプチャです。
画面上にあるのがストップウォッチでタップすることでスタート・ストップ、
ロングタップでリセット出来ます。また、指定時間(2つ設定可能)で振動・テキストの色が変わります。

ボタン類は見たとおりです。PC側のレシーバーソフトで動作を変更することもできます。
これらをタップすることで、スライドを操作します。
また画面では見えませんが、ボリュームボタンや端末をシェイクすることでもスライド送りができます。

画面下の領域は仮想レーザーポインターの操作に使います。
例えば画面右下を触ると、ポインターが左下に移動します。
またボリュームボタンと組み合わせてマウスのようにクリックすることもできます。

年内にはAndroidマーケットにリリースする予定ですので、
Android + Windowsな環境の方はぜひ試してみて感想をお聞かせください。
※快く公開の許可を下さり、ありがとうございました。

せっかくだから俺はAndroidソースコードを読むぜ(1)

どうもこんにちは、コンバット○前です。 嘘です。nakazawa-kです。この数日少しずつ涼しくなってきていますね。 KLab若手エンジニアブログでiPhoneやiPadばかり書かれていてAndroidが 全く書かれていないことに気付いたので、少しずつ勉強した内容などを書いてみます。 現在KLabの社内ではMacユーザ率の上昇に合わせてiPhone開発者増加の 兆しが見えているのですが、開発の取っつきやすさではAndroidだって負けちゃいない。 なんたってMacが無くても不自由なく開発出来る(←ここ重要!)のですから。 というわけで(どういうわけか)Androidなお話です。 今回はカメラからの映像に適当なオーバーレイ要素を追加してリアルタイム エンコードすることがAndroidとそれを走らせているハードウェア上で 実現出来るのか?を調べるためにMediaRecorder関連のソースを追いかけてみました。 ひとつひとつ丹念に見ていけばOSのソースって案外辿って行けて面白いよ!というのをなんとなく感じて頂けると幸いです。
  • Androidは最高の学習環境!?
Androidはご存じの通りオープンソースなモバイル向けOSで、その比較的 新しいコードがAOSP(Android Open Source Project)として公開されています。
ちなみにそのリリース方法はLinuxのカーネル本体とは異なり、Google社が各OS世代の早期パートナー企業(端末メーカ)との間で最新のコードベースでの開発を行い、端末リリース前後のタイミングでAOSPでのコード公開を行う、という流れになっているようです。開発に協力するパートナー企業としては最新OSを搭載した端末を他社に先駆けて市場へ投入出来、またOSに対して自社の望む仕様を公式仕様として追加し易いというメリットが考えられます。
閑話休題、ソースコードが公開されているので、「ここはどういう風に 実装されているんだろう?」という疑問を持った際に、必要であれば OSのコードまでさかのぼって調査することが出来ます。 とはいえ、片っ端からコードの山をひっくり返していけば目的のコードへ 辿り着ける、というわけではありません。なんといってもコード量が莫大です。 gitからソースコードを取得することが出来ますが、AOSPのドキュメントに 従い全て取得すると4.1GB(10/08/30時点)となります。 これ位のコード量になってくると全体に対してgrepをかけるのも一苦労ですし、 検索結果に物凄い数のファイルが見つかって途方に暮れたりするものです。 このような大量のファイルから必要な情報を効率的に得るためには、システムの アーキテクチャ認識を持ち、『必要なものがありそうな場所の勘が働くようにする』 ことが結構重要なことだと思います。 システムの中での呼び出しの流れとデータの流れ(デバイスからの入出力を含め)が 掴めてくると、割と膨大なソースとも付き合いやすくなるのではないでしょうか!? 目の前で動作している端末がどのようなアーキテクチャ、システムで動作しているのかを 学ぶことは非常に良い勉強になるものと思います。せっかくソースコードが 公開されているのでどんどん読みましょう。 ということでだいぶ前置きが長くなってしまいました。nakazawa-kがソースを読み始めたというのが今回の話です。
  • 今回のターゲット:MediaRecorder
先にお断りしておきます。今回の話は、ブログ記事1本分では決着しませんでした。 目的の達成は次回までお預けとなってしまっています。
発端は「Androidのカメラから入力された映像データに対してリアルタイムに オーバーレイをかけ、H.264等で出力することは出来ないものか」と思ったところでした。 ビデオカメラ(CamCoder)といえば通常、MediaRecorder http://developer.android.com/reference/android/media/MediaRecorder.html クラスを用いてソースと出力フォーマット、出力圧縮形式、 出力先を指定した上でstart()を呼んでやれば後は適当にやってくれるという感じです。 逆に、この映像に対して加工を行うことが出来ればARアプリなどで自分の見ていた 世界を動画に記録してそのままYouTubeなどにアップロードする、というような 使い方が出来そうです(ARアプリ内で完結するなら、当然それらをメタデータとして 別途格納しておき、再生時にオーバーレイする方法が考えられますが)。 これを実現するためには
+------------+               +----------------+
| 映像ソース | --フィルタ--> |動画出力エンジン|
+------------+               +----------------+
としてやる必要があります。しかし、残念ながらMediaRecorderで提供されているのは 前述のような入出力設定のみで、実際の動画出力などがどのような仕組みにて 提供されているかは見えなくなっています。
  • 前準備
まずは今回やりたいことがどのようにして実現出来るか、あたりを付けるためにざっと情報を整理してみます。 一般にH.264等のリアルタイムエンコードを行うには携帯端末向けのCPUでは力不足です。そのため、ほとんどの携帯端末ではH.264等の圧縮を丸ごと行う、あるいは部分的にサポートするDSPを用いたエンコードを行っていると考えられます。この入力データに任意のストリームを渡せるのか、それともカメラからの入力を統合チップ内部でバイパスして渡すような方法を採らざるを得ないのか、によって今回の目的の実現可能性は大きく変わってきます(場合によっては一部WindowsMobile機のようにWMVエンコードのソフトウェア実装を持ち込んで力業でエンコードするような方針になります)。 ソースを読み始める前に、少しだけデータシート(というかチップのパンフ的な資料)を見てみましょう。 手元に転がっていたHT-03Aに搭載されている統合チップはMSM7200Aで、どうやら http://www.datasheetpro.com/268119_download_MSM7200A_datasheet.html で見ることが出来ます。 性能的には30fpsでWVGAの動画をキャプチャ出来るほどのチップであることは分かりますが、残念ながら動画エンコード機能に対して任意のストリームを投入出来るか否かについて判断は出来ませんでした。ひょっとすると入力(カメラ)と出力(動画圧縮エンジン)のやりとりをチップ内で完結させなければスループットを出せない(=フレームレートが不足する)かもしれません。 まあ多少フレームサイズやフレームレートが落ちても、加工済みの動画がリアルタイム出力出来れば良いのです。仮にカメラからのJPEG出力系を流用してMJEPGになったとしても、大失敗ではないのです。
  • 本題
それでは、AndroidのMediaRecorderがどのような実装になっているのかを見ていきましょう。 Androidのアーキテクチャは http://developer.android.com/guide/basics/what-is-android.html#os_architecture に記載されているような形になっていています。 今回の場合、Javaで書かれたカメラアプリがAndroid独自のJava系VMである Dalvik Virtual Machineにて実行され、内部からMedia Frameworkが呼び出され、 そこからLinux KernelのCamera DriverやFlash Memory Driverなどを呼び出していると 考えられます。 とりあえず、コードを取得しましょう。
curl http://android.git.kernel.org/repo > repo chmod +x repo sudo mv repo /usr/local/bin repo init -u git://android.git.kernel.org/platform/manifest.git (AOSPのドキュメントではinit-uとなっていますが、正しくは上記の通りです)
まず、おさらいの部分ですがカメラアプリのコードから追いましょう。 アプリケーションのソースはpackages/apps/Camera以下にあります。 MediaRecorderの初期化を行っているのはpackages/apps/Camera/src/com/android/camera/VideoCamera.java VideoCameraクラスのinitializeRecorderメソッドです。

 895         mMediaRecorder = new MediaRecorder();
 896
 897         mMediaRecorder.setCamera(mCameraDevice);
 898         mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 899         mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
 900         mMediaRecorder.setProfile(mProfile);
 901         mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
...
以下、基本的に録画開始を指示するstart()メソッドの流れを追いかけていきます。 次は当然、android.media.MediaRecorderの定義を調べます。 早速すこしずつややこしくなってきます。ほとんどがプロキシのリレーです。 MediaRecorderの実装はほとんどJavaで行われておらず、ネイティブ実装になっています。 Java側のMediaRecorder定義はframeworks/base/media以下にあります。 frameworks/base/media/java/android/media/MediaRecorder.javaでは
 58 public class MediaRecorder
 59 {
 60     static {
 61         System.loadLibrary("media_jni");
 62         native_init();
 63     }
...
513     public native void start() throws IllegalStateException;
との定義がされています。JNIで処理をC系のライブラリに委ねている形です。 これに対応するコードがframeworks/base/media/jni/android_media_MediaRecorder.cppにあります。
339 static void
340 android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)
341 {
342     LOGV("start");
343     sp mr = getMediaRecorder(env, thiz);
344     process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed.");
345 }
...
466     {"start",                "()V",                             (void *)android_media_MediaRecorder_start},
C++側でのMediaRecorderクラスは
421 static void
422 android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
423 {
424     LOGV("setup");
425     sp mr = new MediaRecorder();
で作られます。このあたりは frameworks/base/include/media/mediarecorder.hに定義があります。 各種定数もこのファイルに定義があるので参考になります。 実装はこちらです。frameworks/base/media/libmedia/mediarecorder.cpp このファイルではインスタンスが存在する場合、そのメソッドを呼び出したり 例外処理を行っているだけなので、重要なのはインスタンスの生成部分です。
586 MediaRecorder::MediaRecorder()
587 {
588     LOGV("constructor");
589
590     const sp& service(getMediaPlayerService());
591     if (service != NULL) {
592         mMediaRecorder = service->createMediaRecorder(getpid());
593     }
594     if (mMediaRecorder != NULL) {
595         mCurrentState = MEDIA_RECORDER_IDLE;
596     }
597     doCleanUp();
598 }
この呼び出しはframeworks/base/media/libmediaplayerservice/MediaPlayerService.cppの
 229 sp MediaPlayerService::createMediaRecorder(pid_t pid)
 230 {
 231 #ifndef NO_OPENCORE
 232     sp recorder = new MediaRecorderClient(this, pid);
 233     wp w = recorder;
 234     Mutex::Autolock lock(mLock);
 235     mMediaRecorderClients.add(w);
 236 #else
 237     sp recorder = NULL;
 238 #endif
 239     LOGV("Create new media recorder client from pid %d", pid);
 240     return recorder;
 241 }
に対応しています。ここで、OpenCoreライブラリを利用しない設定でのビルド時には レコーダを無効化しています。MediaRecorderClientクラスを追いかけましょう。 frameworks/base/media/libmediaplayerservice/MediaRecorderClient.cppです。
292 MediaRecorderClient::MediaRecorderClient(const sp& service, pid_t pid)
293 {
294     LOGV("Client constructor");
295     mPid = pid;
296
297 #if BUILD_WITH_FULL_STAGEFRIGHT
298     char value[PROPERTY_VALUE_MAX];
299     if (property_get("media.stagefright.enable-record", value, NULL)
300         && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
301         mRecorder = new StagefrightRecorder;
302     } else
303 #endif
304 #ifndef NO_OPENCORE
305     {
306         mRecorder = new PVMediaRecorder();
307     }
308 #else
309     {
310         mRecorder = NULL;
311     }
312 #endif
313
314     mMediaPlayerService = service;
315 }
OpenCoreが利用出来る際にはPVMediaRecorderを生成していますね。 PVでOpenCoreと来ればpacket-videoのOpenCoreです。OpenCoreはAndroid内で 利用されているマルチメディア処理ライブラリで、公式サイトは http://www.opencore.net/ です。repoコマンドで取得したツリーでは、 external/opencore/doc/にドキュメントも取得されているはずです。 実はここまで読み進めた後でOpenCoreのドキュメントを読まずに external/opencore/engines/author/src/pvauthorengine.cppあたりまで 追いかけてみたのですが、細かな個別実装ばかりが見えてきて全体が 掴みにくくなってきたのでまずはOpenCoreのドキュメントを読み、ざっと 構造を把握してから続きを読むように方針転換しました。 かなり長くなったので今回はこのあたりにして、次回OpenCoreの構造あたりから 続けていきたいと思います。
 KLab若手エンジニアブログのフッター