AS3とRed5で、flv録画環境を作る

USBのWebカメラで、Flash(AS3)のプログラムから動画を撮るやりかたを調べたのでメモ。

Flashによる動画撮影の流れ

Flashで作ったプログラムと、Flash Media Server(FMS)というサーバーソフトウェアを使うことになる。

  1. Flashによるプログラムが動画を撮る。
  2. 撮った動画をFMSに送信。
  3. FMSが、flvファイルとして(サーバー側に)保存。

こんな感じ。Flash自身には動画を保存する機能はなくて、サーバーに送ることしかできない。受け取ったサーバー側がflvファイルを保存することになる。

FMSは高いのでRed5

このFMS、すごく高い。何種類かあって、どれを買えばいいのかよくわかんないけど、どれもすごい高い(60万円とかする)。

そこでRed5。これはFMSのオープンソースの実装なんだそうだ。FMSがどんな機能を持っていて、そのうちどれだけの部分がRed5にも実装されているのかはよくわからないけど、とりあえずFlash側でWebカメラで撮った動画を保存する機能はあるっぽい。

すばらしいなあ。

Red5のインストール

今回は、バージョン0.7.0を使った。0.8.0はRC版が出ているので、近いうちに正式版が出るとは思うけど。

普通にダウンロードしてインストールするだけ。簡単。

Red5の動作確認

Windows版ならサービスとしてインストールされるので、管理ツールのサービスのところにある「Red5」というのを開始させればおk。これでサーバーが起動する。

起動にはちょっと時間がかかる(10〜20秒くらい?)ので慌てずに待つ。

ポート5080でWebサーバーが動き出すので、http://(IPアドレス):5080/ にアクセスすると、なんか以下のような赤いWebページが見えるはず。これが見えれば成功。そこにはデモアプリがたくさんあるので、見てみると面白いと思う。

デモを見る感じだと、動画関連に限らず、複数のブラウザで動くFlashを同期させる技術とかもRed5でやれるっぽい。面白そうだ。

Red5アプリケーションの作成

Flash側から送られてくる動画データを受け取ってflvファイルを出力するアプリケーションを作り、これをRed5で動かすようにする。

Red5自体はJavaで作られていて、Red5上で動かすアプリケーションもJavaで作る。ちなみにFMSはアプリをActionScriptで書くらしい。つまりFMSとRed5のサーバーサイドのアプリは互換していないわけか。Red5上に作ったアプリをFMSで動かしたり、その逆はできない。

で、JavaRed5アプリを作る場合、普通にEclipseが使える。まあEclipseを使うっていうか、できあがったファイルをRed5のフォルダにコピーして動かすだけ。だからデバッガとかは使えないのかな?逆に言うと、別にEclipseRed5を連携させたりするわけじゃないので(そういうEclipseプラグインもあるらしいけどまだ試してない)、EclipseじゃなくNetBeansでもテキストエディタでもなんでもいいと思う。多分。

アプリは作るけど、実装は空っぽ

通信で動画を受け取ってflvで書き込むアプリを書くということで、かなり大変そうだなあとか思ったけど、今回のような場合、アプリのURLさえあれば良い。動画を受け取ってflvで書き出す機能は標準で持っていて、要はFlashが接続してくるためのURLを準備してあげるだけでいいわけだ。

ってことで何もコードを書く必要は無かった。以下その手順。

  1. Eclipseで新しいJavaプロジェクトを作成。
  2. 自動で作られた src は不要なので消す。
  3. Red5インストールフォルダの doc/templates/myapp/WEB-INF をフォルダごとプロジェクト内に持ってくる。
  4. WEB-INF の下に、classessrc を作る。
  5. WEB-INF/src をソースフォルダーにして、WEB-INF/classes を出力フォルダにする。
  6. Add External JARs(外部JARの追加)でRed5インストールフォルダ直下の red5.jar の参照を追加。
  7. WEB-INF/src にパッケージをひとつ作って、Application クラスを作る(スーパークラスorg.red5.server.adapter.ApplicationAdapter にする)。実装は無くて良い(クラスの定義だけで良い)。

ここまでで以下のような感じになる。


各種設定

ここからさらに、設定ファイルをいじっていく。

WEB-INF/red5-web.properties
webapp.contextPath=/flvserver
webapp.virtualHosts=*, localhost, 127.0.0.1
WEB-INF/red5-web.xml

bean要素(id="web.handler"のやつ)を以下のように。

<bean id="web.handler" 
    class="com.nacookan.flvserver.Application" 
    singleton="true" />

それから、bean要素(id="myhandler.service"のやつ)を削除。

WEB-INF/web.xml

まず、context-param要素(param-name要素が"log4jConfigLocation"のやつ)を削除。

そして、context-param要素(param-name要素が"webAppRootKey"のやつ)を以下のように編集。

<context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>/flvserver</param-value>
</context-param>

さらに、listener要素(listener-class要素がorg.springframework.web.util.Log4jConfigListenerのやつ)を削除。

あとservlet要素を削除。

最後にservlet-mapping要素を削除。

Red5への配置と再起動

EclipseWEB-INF フォルダを右クリックして、適当な場所にエクスポートする。それをRed5のインストールフォルダの下の webappsflvserver というフォルダを作り、その中にコピー。

これで終わり。Red5を再起動(サービスの再起動)。

動作確認

とりあえずブラウザから http://(IPアドレス):5080/flvserver/ にアクセスして、以下のような Directory: /flvserver/ のシンプルな画面が出ればおk。

ここまでできれば、サーバー側は終わり。乙。

Flash側の開発

Flashがあればいいけど、無くてもテキストエディタだけでなんとかいける。

以下、全ソースコード

WebCamRecorder.as
// WebCamRecorder.as
package {
    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.net.*;
    public class WebCamRecorder extends Sprite {
        public function WebCamRecorder() {

            var nc:NetConnection = new NetConnection();
            nc.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{
                if(e.info.code != 'NetConnection.Connect.Success') return;

                var cam:Camera = Camera.getCamera();
                cam.setQuality(0, 80);
                cam.setMode(320, 240, 30, true);

                var mic:Microphone = Microphone.getMicrophone();
                mic.rate = 44;

                var ns:NetStream = new NetStream(nc);
                ns.attachCamera(cam);
                ns.attachAudio(mic);
                ns.publish('video', 'record');

                var v:Video = new Video(320, 240);
                v.attachCamera(cam);
                stage.addChild(v); 

                stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void{
                    ns.close();
                    ns.attachCamera(null);
                    ns.attachAudio(null);
                    v.attachCamera(null);
                    stage.removeChild(v);
                    stage.removeEventListener(MouseEvent.CLICK, arguments.callee);
                });
            });
            nc.connect('rtmp://(IPアドレス)/flvserver');
        }
    }
}

以前書いたやり方でAS3の開発環境を作って、自分でコードをコンパイルしてswfを作る。

$ mxmlc WebCamRecorder.as

WebCamRecorder.swfが生成されれば成功。

使ってみる

WebCamRecorder.swf を起動すれば録画が始まって、映像の部分を適当にクリックすれば終了する。ちゃんと音も録音してるよ。

すると、サーバー側の webapps/flvserver/streams/video.flv が生成されているはず。これが今録画したビデオ。

撮った動画をストリーミングで見る

撮った動画を、サーバーからストリーミングで受けとって再生するFlashも作ってみた。

WebCamPlayback.as
//WebCamPlayback.as
package {
    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.net.*;
    public class WebCamPlayback extends Sprite {
        public function WebCamPlayback() {

            var nc:NetConnection = new NetConnection();
            nc.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{
                if(e.info.code != 'NetConnection.Connect.Success') return;

                var ns:NetStream = new NetStream(nc);

                var v:Video = new Video(320, 240);
                v.attachNetStream(ns);
                v.smoothing = true;
                stage.addChild(v);

                ns.client = { onMetaData: function(o:Object):void{} };
                ns.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{
                    if(e.info.code != 'NetStream.Play.Stop') return;

                    ns.close();
                    v.attachNetStream(null);
                    stage.removeChild(v);
                });
                ns.play('video');
            });
            nc.connect('rtmp://(IPアドレス)/flvserver');
        }
    }
}

コンパイルは以下で。

$ mxmlc WebCamPlayback.as

終わり

実際には、上記のコードを自作のFlash内に埋め込んだりして頑張ることになる。まあこれだけ短いコードなので、何をやってるかは把握できると思う。動画のサイズや品質とかをいじるのもわかるだろうし。

いやはや、最初に動画を撮ろうってことになって、Flashでやろうとしたけどファイルの保存ができなくて、調べたらFMSのことを知って、でも高すぎるから断念して、FlashやめてC#で作ろうとして、DirectShowが難しくて断念して、もう一度Flashに戻ってきて、Red5を見つけて、ここまでコードが書けるように修行して、サンプル作ってこうして日記に書くまで、5日ほどかかったわ。